Skip to content
This repository
Browse code

Access control (WIP)

Work in progress of the access control feature:
* You can lock forums and limit posting / access to certain users:
(Members can be specified in a 'members.txt' file)
- 'threads':	Only moderators / members can start threads, but anybody can reply
- 'posts':	Only moderators / members can start threads or reply
- 'private':	Only moderators / members can access and participate in the forum (hidden to the public)
* Moderators can sign-in to do moderator actions
* Moderators can now reply to and append/delete in locked threads
* Moderators can now fully remove previously deleted (blanked-out) comments
  • Loading branch information...
commit 0bee588af09a31b60e2d1fd7f8dff2b908a96e58 1 parent bc03dcd
authored December 01, 2011
2  .gitignore
... ...
@@ -1,5 +1,7 @@
1 1
 *.rss
2 2
 *.xml
3 3
 sticky.txt
  4
+locked.txt
4 5
 mods.txt
  6
+members.txt
5 7
 config.php
11  HISTORY.txt
... ...
@@ -1,3 +1,14 @@
  1
+v8
  2
+*	Access control: Major new feature! You can lock forums and limit posting / access to certain users:
  3
+	(Members can be specified in a 'members.txt' file)
  4
+	- 'threads':	Only moderators / members can start threads, but anybody can reply
  5
+	- 'posts':	Only moderators / members can start threads or reply
  6
+	- 'private':	Only moderators / members can access and participate in the forum (hidden to the public)
  7
+*	Moderators can sign-in to do moderator actions
  8
+*	Moderators can now reply to and append/delete in locked threads
  9
+*	Moderators can now fully remove previously deleted (blanked-out) comments
  10
+*	Config option to disable new user registrations site-wide (`FORUM_NEWBIES`)
  11
+
1 12
 v7	05.NOV.11
2 13
 *	NNF can now be run from a folder, with thanks to Richard van Velzen
3 14
 	(this requires theme changes: URLs must be prepended with `FORUM_PATH`)
59  action.php
@@ -32,15 +32,22 @@
32 32
 	
33 33
 	/* has the un/pw been submitted to authenticate the append?
34 34
 	   -------------------------------------------------------------------------------------------------------------- */
35  
-	if (
36  
-		NAME && PASS && AUTH
37  
-		//only a moderator, or the post originator can append to a post
38  
-		&& (isMod (NAME) || NAME == (string) $post->author)
39  
-		//cannot append to a deleted post
40  
-		&& !(bool) $post->xpath ("category[text()='deleted']")
41  
-		//cannot append to a locked thread
42  
-		&& !$xml->channel->xpath ("category[text()='locked']")
43  
-	) {	
  35
+	if (AUTH && TEXT && FORUM_ENABLED && (
  36
+		//- if the thread is unlocked and the forum is either unlocked or thread-locked (anybody can reply)
  37
+		(!(bool) $xml->channel->xpath ("category[text()='locked']") && (!FORUM_LOCK || FORUM_LOCK == 'threads')) ||
  38
+		//- if the thread is locked, but you are a moderator (signed in)
  39
+		((bool) $xml->channel->xpath ("category[text()='locked']") && CAN_MOD) ||
  40
+		//- if the forum is post-locked, but you are a moderator (signed in) or member
  41
+		(FORUM_LOCK == 'posts' && (CAN_MOD || isMember (NAME)))
  42
+	) && (
  43
+		//a moderator can always append
  44
+		isMod (NAME) ||
  45
+		//the owner of a post can append
  46
+		(strtolower (NAME) == strtolower ($post->author) && (
  47
+			//if the forum is post-locked, they must be a member to append to their own posts
  48
+			(!FORUM_LOCK || FORUM_LOCK == 'threads') || isMember (NAME)
  49
+		))
  50
+	)) {
44 51
 		$now = time ();
45 52
 		$post->description .= "\n".template_tags (TEMPLATE_APPEND, array (
46 53
 			'AUTHOR'	=> safeHTML (NAME),
@@ -129,17 +136,29 @@
129 136
 	
130 137
 	/* has the un/pw been submitted to authenticate the delete?
131 138
 	   -------------------------------------------------------------------------------------------------------------- */
132  
-	if (
133  
-		NAME && PASS && AUTH
134  
-		//only a moderator, or the post originator can delete a post/thread
135  
-		&& (isMod (NAME) || NAME == (string) $post->author)
136  
-		//cannot delete a locked thread
137  
-		&& !$xml->channel->xpath ("category[text()='locked']")
138  
-		
  139
+	if (AUTH && FORUM_ENABLED && (
  140
+		//- if the thread is unlocked and the forum is either unlocked or thread-locked (anybody can reply)
  141
+		(!(bool) $xml->channel->xpath ("category[text()='locked']") && (!FORUM_LOCK || FORUM_LOCK == 'threads')) ||
  142
+		//- if the thread is locked, but you are a moderator (signed in)
  143
+		((bool) $xml->channel->xpath ("category[text()='locked']") && CAN_MOD) ||
  144
+		//- if the forum is post-locked, but you are a moderator (signed in) or member
  145
+		(FORUM_LOCK == 'posts' && (CAN_MOD || isMember (NAME)))
  146
+	) && (
  147
+		//a moderator can always delete
  148
+		isMod (NAME) ||
  149
+		//the owner of a post can delete
  150
+		(strtolower (NAME) == strtolower ($post->author) && (
  151
+			//if the forum is post-locked, they must be a member to delete their own posts
  152
+			(!FORUM_LOCK || FORUM_LOCK == 'threads') || isMember (NAME)
  153
+		))
139 154
 	//deleting a post?
140  
-	) if ($ID) {
  155
+	)) if ($ID) {
141 156
 		//full delete? (option ticked, is moderator, and post is on the last page)
142  
-		if (isset ($_POST['remove']) && isMod (NAME) && $i <= (count ($xml->channel->item)-2) % FORUM_POSTS) {
  157
+		if (
  158
+			(isMod (NAME) && $i <= (count ($xml->channel->item)-2) % FORUM_POSTS) &&
  159
+			//if the post has already been blanked, delete it fully
  160
+			(isset ($_POST['remove']) || $post->xpath ("category[text()='deleted']"))
  161
+		) {
143 162
 			//remove the post from the thread entirely
144 163
 			unset ($xml->channel->item[$i]);
145 164
 			
@@ -225,7 +244,7 @@
225 244
 	$FILE = (preg_match ('/^[^.\/]+$/', @$_GET['file']) ? $_GET['file'] : '') or die ('Malformed request');
226 245
 	
227 246
 	//get a write lock on the file so that between now and saving, no other posts could slip in
228  
-	$f = fopen ("$FILE.rss", 'c'); flock ($f, LOCK_EX);
  247
+	$f   = fopen ("$FILE.rss", 'c'); flock ($f, LOCK_EX);
229 248
 	$xml = simplexml_load_file ("$FILE.rss") or die ('Invalid file');
230 249
 	
231 250
 	//what’s the current status?
@@ -233,7 +252,7 @@
233 252
 	
234 253
 	/* has the un/pw been submitted to authenticate the un/lock? (only a moderator can un/lock a thread)
235 254
 	   -------------------------------------------------------------------------------------------------------------- */
236  
-	if (NAME && PASS && AUTH && isMod (NAME)) {
  255
+	if (CAN_MOD && AUTH) {
237 256
 		if ($LOCKED) {
238 257
 			//if there’s a "locked" category, remove it
239 258
 			//note: for simplicity this removes *all* channel categories as NNF only uses one atm,
3  config.example.php
@@ -8,6 +8,9 @@
8 8
 
9 9
 /* --- copy this file as 'config.php' and customise to your liking --- */
10 10
 
  11
+//uncomment this if you want to show PHP errors in the browser
  12
+#error_reporting (-1);
  13
+
11 14
 //forum’s title. used in theme, and in RSS feeds
12 15
 //WARNING: changing this won’t update the index RSS feed containing this name; delete 'index.xml' and then post/delete
13 16
 //         a thread to regenerate the 'index.xml' file so as to see the change
6  index.php
@@ -18,7 +18,7 @@
18 18
 /* ====================================================================================================================== */
19 19
 
20 20
 //has the user submitted a new thread? (and is the info valid?)
21  
-if (FORUM_ENABLED && NAME && PASS && AUTH && TITLE && TEXT && @$_POST['email'] == 'example@abc.com') {
  21
+if (CAN_POST && AUTH && TITLE && TEXT && @$_POST['email'] == 'example@abc.com') {
22 22
 	//the file on disk is a simplified version of the title:
23 23
 	$translit = preg_replace (
24 24
 		//replace non alphanumerics with underscores and don’t use more than 2 in a row
@@ -79,7 +79,7 @@
79 79
 /* ====================================================================================================================== */
80 80
 /* sub-forums
81 81
    ---------------------------------------------------------------------------------------------------------------------- */
82  
-//don’t all sub-sub-forums
  82
+//don’t allow sub-sub-forums (yet)
83 83
 if (!PATH) foreach (array_filter (
84 84
 	//get a list of folders:
85 85
 	//include only directories, but ignore directories starting with ‘.’ and the users / themes folders
@@ -161,7 +161,7 @@
161 161
 /* new thread form
162 162
    ---------------------------------------------------------------------------------------------------------------------- */
163 163
 //(exclude if posting has been disabled)
164  
-if (FORUM_ENABLED) $FORM = array (
  164
+if (CAN_POST) $FORM = array (
165 165
 	'NAME'	=> safeString (NAME),
166 166
 	'PASS'	=> safeString (PASS),
167 167
 	'TITLE'	=> safeString (TITLE),
150  shared.php
@@ -5,22 +5,22 @@
5 5
    you may do whatever you want to this code as long as you give credit to Kroc Camen, <camendesign.com>
6 6
 */
7 7
 
8  
-//let me know when I’m being stupid
9  
-error_reporting (-1);
10  
-
11 8
 //default UTF-8 throughout
12 9
 mb_internal_encoding ('UTF-8');
13 10
 mb_regex_encoding    ('UTF-8');
14 11
 
15 12
 /* constants: some stuff we don’t expect to change
16 13
    ---------------------------------------------------------------------------------------------------------------------- */
17  
-define ('START', 		microtime (true));			//record how long the page takes to generate
18 14
 define ('FORUM_ROOT',		dirname (__FILE__));			//full server-path for absolute references
19 15
 define ('FORUM_PATH',							//relative from webroot--if running in a folder
20 16
 	str_replace ('//', '/', dirname ($_SERVER['SCRIPT_NAME']).'/')	//(always starts with a slash and ends in one)
21 17
 );
22 18
 define ('FORUM_URL',		'http://'.$_SERVER['HTTP_HOST']);	//todo: https support
23 19
 
  20
+//for HTTP authentication (private forums)
  21
+define ('HTTP_AUTH_UN',		@$_SERVER['PHP_AUTH_USER']);		//username if using HTTP authentication
  22
+define ('HTTP_AUTH_PW',		@$_SERVER['PHP_AUTH_PW']);		//password if using HTTP authentication
  23
+
24 24
 //these are just some enums for templates to react to
25 25
 define ('ERROR_NONE',		0);
26 26
 define ('ERROR_NAME',		1);					//name entered is invalid / blank
@@ -59,54 +59,108 @@
59 59
 date_default_timezone_set (FORUM_TIMEZONE);
60 60
 
61 61
 
62  
-/* get input
  62
+/* common input
63 63
    ====================================================================================================================== */
64  
-//all pages can accept a name / password when committing actions (new thread / post &c.)
65  
-define ('NAME', safeGet (@$_POST['username'], SIZE_NAME));
66  
-define ('PASS', safeGet (@$_POST['password'], SIZE_PASS, false));
  64
+//all our pages use path (often optional) so this is done here
  65
+define ('PATH', preg_match ('/[^.\/&]+/', @$_GET['path']) ? $_GET['path'] : '');
  66
+//these two get used an awful lot
  67
+define ('PATH_URL', !PATH ? FORUM_PATH : safeURL (FORUM_PATH.PATH.'/', false));	//when outputting as part of a URL
  68
+define ('PATH_DIR', !PATH ? '/' : '/'.PATH.'/');				//serverside, like `chdir` / `unlink`
  69
+
  70
+//we have to change directory for `is_dir` to work, see <uk3.php.net/manual/en/function.is-dir.php#70005>
  71
+//being in the right directory is also assumed for reading 'mods.txt' and when generating the RSS (`indexRSS`)
  72
+//(oddly with `chdir` the path must end in a slash)
  73
+@chdir (FORUM_ROOT.PATH_DIR) or die ("Invalid path");
  74
+
67 75
 
68  
-//if name & password are provided, validate them
69  
-if (
  76
+/* access control
  77
+   ====================================================================================================================== */
  78
+/* name / password authorisation:
  79
+   ---------------------------------------------------------------------------------------------------------------------- */
  80
+//all pages can accept a name / password when committing actions (new thread / post &c.)
  81
+//in the case of HTTP authentication (sign in / private forums), these are provided in the request header
  82
+define ('NAME', HTTP_AUTH_UN ? HTTP_AUTH_UN : safeGet (@$_POST['username'], SIZE_NAME));
  83
+define ('PASS', HTTP_AUTH_PW ? HTTP_AUTH_PW : safeGet (@$_POST['password'], SIZE_PASS, false));
  84
+
  85
+if ((
  86
+	//if any HTTP authentication is given, we don’t need to validate form fields
  87
+	HTTP_AUTH_UN && HTTP_AUTH_PW
  88
+) || (
  89
+	//if an input form was submitted:
70 90
 	NAME && PASS &&
71 91
 	//the email check is a fake hidden field in the form to try and fool spam bots
72 92
 	isset ($_POST['email']) && @$_POST['email'] == 'example@abc.com' &&
73 93
 	//I wonder what this does...?
74 94
 	((isset ($_POST['x']) && isset ($_POST['y'])) || (isset ($_POST['submit_x']) && isset ($_POST['submit_y'])))
75  
-) {
  95
+)) {
76 96
 	//users are stored as text files based on the hash of the given name
77 97
 	$name = hash ('sha512', strtolower (NAME));
78 98
 	$user = FORUM_ROOT."/users/$name.txt";
79  
-	//create the user, if new (if registrations are allowed)
80  
-	if (FORUM_NEWBIES && !file_exists ($user)) file_put_contents ($user, hash ('sha512', $name.PASS));
  99
+	
  100
+	//create the user, if new:
  101
+	//- if registrations are allowed (`FORUM_NEWBIES`)
  102
+	//- you can’t create new users with the HTTP_AUTH sign in
  103
+	if (FORUM_NEWBIES && !HTTP_AUTH_UN && !file_exists ($user)) file_put_contents ($user, hash ('sha512', $name.PASS));
  104
+	
81 105
 	//does password match?
82 106
 	define ('AUTH', @file_get_contents ($user) == hash ('sha512', $name.PASS));
  107
+	
  108
+	//if signed in with HTTP_AUTH, confirm that it’s okay to use
  109
+	//(e.g. the user could still have given the wrong password with HTTP_AUTH)
  110
+	define ('HTTP_AUTH', HTTP_AUTH_UN ? AUTH : false);
83 111
 } else {
84  
-	define ('AUTH', false);
  112
+	define ('AUTH',      false);
  113
+	define ('HTTP_AUTH', false);
85 114
 }
86 115
 
87  
-//all our pages use path (often optional) so this is done here
88  
-define ('PATH', preg_match ('/[^.\/&]+/', @$_GET['path']) ? $_GET['path'] : '');
89  
-//these two get used an awful lot
90  
-define ('PATH_URL', !PATH ? FORUM_PATH : safeURL (FORUM_PATH.PATH.'/', false));	//when outputting as part of a URL
91  
-define ('PATH_DIR', !PATH ? '/' : '/'.PATH.'/');				//serverside, like `chdir` / `unlink`
  116
+//get the lock status of the current forum we’re in:
  117
+//"threads"	- only users in "mods.txt" / "members.txt" can start threads, but anybody can reply
  118
+//"posts"	- only users in "mods.txt" / "members.txt" can start threads or reply
  119
+//"private"	- only users in "mods.txt" / "members.txt" can enter and use the forum, it is hidden from everybody else
  120
+define ('FORUM_LOCK', trim (@file_get_contents ('locked.txt')));
92 121
 
93  
-//we have to change directory for `is_dir` to work, see <uk3.php.net/manual/en/function.is-dir.php#70005>
94  
-//being in the right directory is also assumed for reading 'mods.txt' and when generating the RSS (`indexRSS`)
95  
-//(oddly with `chdir` the path must end in a slash)
96  
-@chdir (FORUM_ROOT.PATH_DIR) or die ("Invalid path");
  122
+//if the sign-in link was clicked, invoke a HTTP_AUTH request in the browser
  123
+if (!HTTP_AUTH && isset ($_GET['login'])) {
  124
+	header ('WWW-Authenticate: Basic');
  125
+	header ('HTTP/1.0 401 Unauthorized');
  126
+}
97 127
 
  128
+/* access rights
  129
+   ---------------------------------------------------------------------------------------------------------------------- */
98 130
 //get the list of moderators:
99 131
 $MODS = array (
100  
-	//mods.txt on root for mods on all sub-forums
  132
+	//'mods.txt' on root for mods on all sub-forums
101 133
 	'GLOBAL'=> file_exists (FORUM_ROOT.'/mods.txt')
102 134
 		? file (FORUM_ROOT.'/mods.txt', FILE_IGNORE_NEW_LINES + FILE_SKIP_EMPTY_LINES)
103 135
 		: array (),
104  
-	//if in a sub-forum, the local mods.txt
  136
+	//if in a sub-forum, the local 'mods.txt'
105 137
 	'LOCAL'	=> PATH && file_exists ('mods.txt')
106 138
 		? file ('mods.txt', FILE_IGNORE_NEW_LINES + FILE_SKIP_EMPTY_LINES)
107 139
 		: array ()
108 140
 );
109 141
 
  142
+//get the list (if any) of users allowed to access this current forum
  143
+$MEMBERS = file_exists ('members.txt') ? file ('members.txt', FILE_IGNORE_NEW_LINES + FILE_SKIP_EMPTY_LINES) : array ();
  144
+
  145
+//can the current user moderate in this forum?
  146
+define ('CAN_MOD', HTTP_AUTH ? isMod (NAME) : false);
  147
+
  148
+//can the current user post new threads in the current forum?
  149
+//(posting replies is dependent on the the thread -- if locked -- so tested in 'thread.php')
  150
+define ('CAN_POST', FORUM_ENABLED && (
  151
+	//- if the user is a moderator or member of the current forum, they can post
  152
+	CAN_MOD || isMember (NAME) ||
  153
+	//- if the forum is unlocked (mods will have to log in to see the form)
  154
+	!FORUM_LOCK
  155
+));
  156
+
  157
+//if the forum is private, check the current user and issue an auth request if not signed in or allowed
  158
+if (FORUM_LOCK == 'private' && !(CAN_MOD || isMember (NAME))) {
  159
+	header ('WWW-Authenticate: Basic');
  160
+	header ('HTTP/1.0 401 Unauthorized');
  161
+	//todo: a proper error page, if I make a splash/login screen for a private root-forum
  162
+	die ("Authorisation required.");
  163
+}
110 164
 
111 165
 /* ---------------------------------------------------------------------------------------------------------------------- */
112 166
 
@@ -114,22 +168,6 @@
114 168
 header ('Cache-Control: no-cache', true);
115 169
 header ('Expires: 0', true);
116 170
 
117  
-
118  
-/* ====================================================================================================================== */
119  
-
120  
-//<stackoverflow.com/questions/2092012/simplexml-how-to-prepend-a-child-in-a-node/2093059#2093059>
121  
-//we could of course do all the XML manipulation in DOM proper to save doing this…
122  
-class allow_prepend extends SimpleXMLElement {
123  
-	public function prependChild ($name, $value=null) {
124  
-		$dom = dom_import_simplexml ($this);
125  
-		$new = $dom->insertBefore (
126  
-			$dom->ownerDocument->createElement ($name, $value),
127  
-			$dom->firstChild
128  
-		);
129  
-		return simplexml_import_dom ($new, get_class ($this));
130  
-	}
131  
-}
132  
-
133 171
 /* ====================================================================================================================== */
134 172
 
135 173
 //sanitise input:
@@ -165,7 +203,7 @@ function template_tags ($template, $values) {
165 203
 	return $template;
166 204
 }
167 205
 
168  
-//produces a truncated list of pages around the current page
  206
+//produces a truncated list of page numbers around the current page
169 207
 function pageList ($current, $total) {
170 208
 	//always include the first page
171 209
 	$PAGES[] = 1;
@@ -273,12 +311,17 @@ function formatText ($text) {
273 311
 
274 312
 /* ====================================================================================================================== */
275 313
 
276  
-//check to see if a name is a known moderator in mods.txt
  314
+//check to see if a name is a known moderator in 'mods.txt'
277 315
 function isMod ($name) {
278 316
 	global $MODS;
279 317
 	return in_array (strtolower ($name), array_map ('strtolower', $MODS['GLOBAL'] + $MODS['LOCAL']));
280 318
 }
281 319
 
  320
+function isMember ($name) {
  321
+	global $MEMBERS;
  322
+	return in_array (strtolower ($name), array_map ('strtolower', $MEMBERS));
  323
+}
  324
+
282 325
 /* ====================================================================================================================== */
283 326
 
284 327
 //regenerate a folder's RSS file (all changes happening in a folder)
@@ -330,11 +373,11 @@ function indexRSS () {
330 373
 	
331 374
 	/* sitemap
332 375
 	   -------------------------------------------------------------------------------------------------------------- */
  376
+	//we’re going to use the RSS files as sitemaps
333 377
 	chdir (FORUM_ROOT);
334 378
 	
335  
-	//we’re going to use the RSS files as sitemaps
336  
-	$folders = array ('');
337 379
 	//get list of sub-forums
  380
+	$folders = array ('');
338 381
 	foreach (array_filter (
339 382
 		//include only directories, but ignore directories starting with ‘.’ and the users / themes folders
340 383
 		preg_grep ('/^(\.|users$|themes$)/', scandir (FORUM_ROOT.'/'), PREG_GREP_INVERT), 'is_dir'
@@ -370,4 +413,19 @@ function indexRSS () {
370 413
 	clearstatcache ();
371 414
 }
372 415
 
373  
-?>
  416
+/* ====================================================================================================================== */
  417
+
  418
+//<stackoverflow.com/questions/2092012/simplexml-how-to-prepend-a-child-in-a-node/2093059#2093059>
  419
+//we could of course do all the XML manipulation in DOM proper to save doing this…
  420
+class allow_prepend extends SimpleXMLElement {
  421
+	public function prependChild ($name, $value=null) {
  422
+		$dom = dom_import_simplexml ($this);
  423
+		$new = $dom->insertBefore (
  424
+			$dom->ownerDocument->createElement ($name, $value),
  425
+			$dom->firstChild
  426
+		);
  427
+		return simplexml_import_dom ($new, get_class ($this));
  428
+	}
  429
+}
  430
+
  431
+?>
30  themes/greyscale/append.inc.php
@@ -117,23 +117,28 @@
117 117
 <!-- =================================================================================================================== -->
118 118
 <div id="mods">
119 119
 <?php if (!empty ($MODS['LOCAL'])): ?>
120  
-<p>
121  
-	Moderators for this sub-forum:
122  
-	<b class="mod"><?php echo implode ('</b>, <b class="mod">', array_map ('safeHTML', $MODS['LOCAL']))?></b>
123  
-</p>
124  
-<?php endif; ?>
125  
-<?php if (!empty ($MODS['GLOBAL'])): ?>
126  
-<p>
127  
-	Your friendly neighbourhood moderators:
128  
-	<b class="mod"><?php echo implode ('</b>, <b class="mod">', array_map ('safeHTML', $MODS['GLOBAL']))?></b>
129  
-</p>
  120
+	<p>
  121
+		Moderators for this sub-forum:
  122
+		<b class="mod"><?php echo implode ('</b>, <b class="mod">', array_map ('safeHTML', $MODS['LOCAL']))?></b>
  123
+	</p>
  124
+<?php endif;
  125
+      if (!empty ($MODS['GLOBAL'])): ?>
  126
+	<p>
  127
+		Your friendly neighbourhood moderators:
  128
+		<b class="mod"><?php echo implode ('</b>, <b class="mod">', array_map ('safeHTML', $MODS['GLOBAL']))?></b>
  129
+	</p>
  130
+<?php endif;
  131
+      if (!empty ($MEMBERS)): ?>
  132
+	<p>
  133
+		Members of this forum:
  134
+		<b><?php echo implode ('</b>, <b>', array_map ('safeHTML', $MEMBERS))?></b>
  135
+	</p>
130 136
 <?php endif; ?>
131 137
 </div>
132 138
 <footer><p>
133 139
 	Powered by <a href="http://camendesign.com/nononsense_forum">NoNonsense Forum</a><br />
134 140
 	© Kroc Camen of <a href="http://camendesign.com">Camen Design</a>
135 141
 </p></footer>
136  
-<div id="grid"></div>
137 142
 <script>
138 143
 //in iOS tapping a label doesn't click the related input element, we'll add this back in using JavaScript
139 144
 if (document.getElementsByTagName !== undefined) {
@@ -142,5 +147,4 @@
142 147
 	for (i=0; i<labels.length; i++) if (labels[i].getAttribute ("for")) labels[i].onclick = function (){}
143 148
 }
144 149
 </script>
145  
-<!-- page generated in: <?php echo round (microtime (true) - START, 3)?>s -->
146  
-</body>
  150
+</body>
30  themes/greyscale/delete.inc.php
@@ -119,23 +119,28 @@
119 119
 <!-- =================================================================================================================== -->
120 120
 <div id="mods">
121 121
 <?php if (!empty ($MODS['LOCAL'])): ?>
122  
-<p>
123  
-	Moderators for this sub-forum:
124  
-	<b class="mod"><?php echo implode ('</b>, <b class="mod">', array_map ('safeHTML', $MODS['LOCAL']))?></b>
125  
-</p>
126  
-<?php endif; ?>
127  
-<?php if (!empty ($MODS['GLOBAL'])): ?>
128  
-<p>
129  
-	Your friendly neighbourhood moderators:
130  
-	<b class="mod"><?php echo implode ('</b>, <b class="mod">', array_map ('safeHTML', $MODS['GLOBAL']))?></b>
131  
-</p>
  122
+	<p>
  123
+		Moderators for this sub-forum:
  124
+		<b class="mod"><?php echo implode ('</b>, <b class="mod">', array_map ('safeHTML', $MODS['LOCAL']))?></b>
  125
+	</p>
  126
+<?php endif;
  127
+      if (!empty ($MODS['GLOBAL'])): ?>
  128
+	<p>
  129
+		Your friendly neighbourhood moderators:
  130
+		<b class="mod"><?php echo implode ('</b>, <b class="mod">', array_map ('safeHTML', $MODS['GLOBAL']))?></b>
  131
+	</p>
  132
+<?php endif;
  133
+      if (!empty ($MEMBERS)): ?>
  134
+	<p>
  135
+		Members of this forum:
  136
+		<b><?php echo implode ('</b>, <b>', array_map ('safeHTML', $MEMBERS))?></b>
  137
+	</p>
132 138
 <?php endif; ?>
133 139
 </div>
134 140
 <footer><p>
135 141
 	Powered by <a href="http://camendesign.com/nononsense_forum">NoNonsenseForum</a><br />
136 142
 	© Kroc Camen of <a href="http://camendesign.com">Camen Design</a>
137 143
 </p></footer>
138  
-<div id="grid"></div>
139 144
 <script>
140 145
 //in iOS tapping a label doesn't click the related input element, we'll add this back in using JavaScript
141 146
 if (document.getElementsByTagName !== undefined) {
@@ -144,5 +149,4 @@
144 149
 	for (i=0; i<labels.length; i++) if (labels[i].getAttribute ("for")) labels[i].onclick = function (){}
145 150
 }
146 151
 </script>
147  
-<!-- page generated in: <?php echo round (microtime (true) - START, 3)?>s -->
148  
-</body>
  152
+</body>
78  themes/greyscale/index.inc.php
@@ -44,10 +44,13 @@
44 44
 	--></form>
45 45
 	
46 46
 	<nav><p>
  47
+<?php if (CAN_POST):?>
47 48
 		<a id="add" href="#new">Add Thread</a>
  49
+<?php endif;?>
48 50
 		<a id="rss" href="<?php echo FORUM_PATH?>index.xml">RSS</a>
49 51
 	</p><p>
50 52
 		<a id="index" href="<?php echo FORUM_PATH?>">Index</a><?php if (PATH): ?> » <?php echo PATH?><?php endif; ?>
  53
+
51 54
 	</p></nav>
52 55
 </header>
53 56
 <!-- =================================================================================================================== -->
@@ -66,6 +69,20 @@
66 69
 </section>
67 70
 <?php endif; ?>
68 71
 
  72
+<?php if (FORUM_LOCK == 'threads'): ?>
  73
+<p id="rights">
  74
+	Only <a href="#mods">moderators or members</a> can start new threads here, but anybody can reply to existing threads.
  75
+</p>
  76
+<?php elseif (FORUM_LOCK == 'posts'): ?>
  77
+<p id="rights">
  78
+	Only <a href="#mods">moderators or members</a> can participate here.
  79
+</p>
  80
+<?php elseif (FORUM_LOCK == 'private'): ?>
  81
+<p id="rights">
  82
+	Only <a href="#mods">moderators or members</a> can access and participate here.
  83
+</p>
  84
+<?php endif;?>
  85
+
69 86
 <?php if (isset ($THREADS)): ?>
70 87
 <section id="threads">
71 88
 	<h1>Threads</h1>
@@ -87,11 +104,11 @@
87 104
 	<nav><ol class="pages"><?php echo $PAGES?></ol></nav>
88 105
 </section>
89 106
 <?php endif; ?>
  107
+<?php if (CAN_POST): ?>
90 108
 <!-- =================================================================================================================== -->
91 109
 <section id="new">
92 110
 	<h1>Add Thread</h1>
93 111
 	<form method="post" action="#new" enctype="application/x-www-form-urlencoded;charset=utf-8" autocomplete="on">
94  
-<?php if (FORUM_ENABLED): ?>
95 112
 		<p id="ptitle">
96 113
 			<label for="title">Title:</label>
97 114
 			<input name="title" id="title" type="text" size="28" tabindex="1"
@@ -100,7 +117,13 @@
100 117
 		</p>
101 118
 		
102 119
 		<div id="rightcol">
103  
-		
  120
+<?php if (HTTP_AUTH): ?>
  121
+		<label for="user">You are signed in as:</label>
  122
+		<p id="puser">
  123
+			<input name="username" id="user" type="text" size="28" maxlength="<?php echo SIZE_NAME ?>"
  124
+			       disabled value="<?php echo HTTP_AUTH_UN ?>" />
  125
+		</p>
  126
+<?php else: ?>
104 127
 		<p id="puser">
105 128
 			<label for="user">Name:</label>
106 129
 			<input name="username" id="user" type="text" size="28" tabindex="3"
@@ -116,12 +139,17 @@
116 139
 			<input name="email" type="text" value="example@abc.com" tabindex="0" required autocomplete="off" />
117 140
 			(Leave this as-is, it’s a trap!)
118 141
 		</p>
  142
+<?php endif; ?>
119 143
 <?php switch ($FORM['ERROR']):
120 144
 	case ERROR_NONE:
121  
-	if (FORUM_NEWBIES): ?>
122  
-		<p id="ok">There is no need to “register”, just enter the same name + password of your choice every time.</p>
123  
-<?php	else :?>
  145
+	//if signed in, there's no password field
  146
+	if (HTTP_AUTH): ?>
  147
+		<p id="ok">(Quit your browser or clear the browser cache to sign out.)</p>
  148
+<?php	//if new users are not allowed
  149
+	elseif (!FORUM_NEWBIES): ?>
124 150
 		<p id="error">Only registered users can post.<br />No new registrations are allowed.</p>
  151
+<?php	else: ?>
  152
+		<p id="ok">There is no need to “register”, just enter the same name + password of your choice every time.</p>
125 153
 <?php	endif;
126 154
 	break;
127 155
 	case ERROR_NAME: ?>
@@ -160,31 +188,40 @@
160 188
 			<input id="submit" name="submit" type="image" src="<?php echo FORUM_PATH?>themes/<?php echo FORUM_THEME?>/icons/submit.png"
161 189
 			       width="40" height="40" tabindex="5" value="&gt;" />
162 190
 		</label></p>
163  
-<?php else: ?>
164  
-		<p id="error">Sorry, posting is currently disabled.</p>
165  
-<?php endif; ?>
166 191
 	</form>
167 192
 </section>
  193
+<?php endif; ?>
168 194
 <!-- =================================================================================================================== -->
169 195
 <div id="mods">
170 196
 <?php if (!empty ($MODS['LOCAL'])): ?>
171  
-<p>
172  
-	Moderators for this sub-forum:
173  
-	<b class="mod"><?php echo implode ('</b>, <b class="mod">', array_map ('safeHTML', $MODS['LOCAL']))?></b>
174  
-</p>
175  
-<?php endif; ?>
176  
-<?php if (!empty ($MODS['GLOBAL'])): ?>
177  
-<p>
178  
-	Your friendly neighbourhood moderators:
179  
-	<b class="mod"><?php echo implode ('</b>, <b class="mod">', array_map ('safeHTML', $MODS['GLOBAL']))?></b>
180  
-</p>
  197
+	<p>
  198
+		Moderators for this sub-forum:
  199
+		<b class="mod"><?php echo implode ('</b>, <b class="mod">', array_map ('safeHTML', $MODS['LOCAL']))?></b>
  200
+	</p>
  201
+<?php endif;
  202
+      if (!empty ($MODS['GLOBAL'])): ?>
  203
+	<p>
  204
+		Your friendly neighbourhood moderators:
  205
+		<b class="mod"><?php echo implode ('</b>, <b class="mod">', array_map ('safeHTML', $MODS['GLOBAL']))?></b>
  206
+	</p>
  207
+<?php endif;
  208
+      if (!empty ($MEMBERS)): ?>
  209
+	<p>
  210
+		Members of this forum:
  211
+		<b><?php echo implode ('</b>, <b>', array_map ('safeHTML', $MEMBERS))?></b>
  212
+	</p>
181 213
 <?php endif; ?>
182 214
 </div>
183 215
 <footer><p>
184 216
 	Powered by <a href="http://camendesign.com/nononsense_forum">NoNonsense Forum</a><br />
185 217
 	© Kroc Camen of <a href="http://camendesign.com">Camen Design</a>
  218
+</p><p id="login">
  219
+<?php if (HTTP_AUTH): ?>
  220
+	Signed in as: <b><?php echo safeHTML (HTTP_AUTH_UN); ?></b>
  221
+<?php else: ?>
  222
+	<a href="?login">Sign in</a>
  223
+<?php endif; ?>
186 224
 </p></footer>
187  
-<div id="grid"></div>
188 225
 <script>
189 226
 //in iOS tapping a label doesn't click the related input element, we'll add this back in using JavaScript
190 227
 if (document.getElementsByTagName !== undefined) {
@@ -193,5 +230,4 @@
193 230
 	for (i=0; i<labels.length; i++) if (labels[i].getAttribute ("for")) labels[i].onclick = function (){}
194 231
 }
195 232
 </script>
196  
-<!-- page generated in: <?php echo round (microtime (true) - START, 3)?>s -->
197  
-</body>
  233
+</body>
30  themes/greyscale/lock.inc.php
@@ -86,23 +86,28 @@
86 86
 <!-- =================================================================================================================== -->
87 87
 <div id="mods">
88 88
 <?php if (!empty ($MODS['LOCAL'])): ?>
89  
-<p>
90  
-	Moderators for this sub-forum:
91  
-	<b class="mod"><?php echo implode ('</b>, <b class="mod">', array_map ('safeHTML', $MODS['LOCAL']))?></b>
92  
-</p>
93  
-<?php endif; ?>
94  
-<?php if (!empty ($MODS['GLOBAL'])): ?>
95  
-<p>
96  
-	Your friendly neighbourhood moderators:
97  
-	<b class="mod"><?php echo implode ('</b>, <b class="mod">', array_map ('safeHTML', $MODS['GLOBAL']))?></b>
98  
-</p>
  89
+	<p>
  90
+		Moderators for this sub-forum:
  91
+		<b class="mod"><?php echo implode ('</b>, <b class="mod">', array_map ('safeHTML', $MODS['LOCAL']))?></b>
  92
+	</p>
  93
+<?php endif;
  94
+      if (!empty ($MODS['GLOBAL'])): ?>
  95
+	<p>
  96
+		Your friendly neighbourhood moderators:
  97
+		<b class="mod"><?php echo implode ('</b>, <b class="mod">', array_map ('safeHTML', $MODS['GLOBAL']))?></b>
  98
+	</p>
  99
+<?php endif;
  100
+      if (!empty ($MEMBERS)): ?>
  101
+	<p>
  102
+		Members of this forum:
  103
+		<b><?php echo implode ('</b>, <b>', array_map ('safeHTML', $MEMBERS))?></b>
  104
+	</p>
99 105
 <?php endif; ?>
100 106
 </div>
101 107
 <footer><p>
102 108
 	Powered by <a href="http://camendesign.com/nononsense_forum">NoNonsenseForum</a><br />
103 109
 	© Kroc Camen of <a href="http://camendesign.com">Camen Design</a>
104 110
 </p></footer>
105  
-<div id="grid"></div>
106 111
 <script>
107 112
 //in iOS tapping a label doesn't click the related input element, we'll add this back in using JavaScript
108 113
 if (document.getElementsByTagName !== undefined) {
@@ -111,5 +116,4 @@
111 116
 	for (i=0; i<labels.length; i++) if (labels[i].getAttribute ("for")) labels[i].onclick = function (){}
112 117
 }
113 118
 </script>
114  
-<!-- page generated in: <?php echo round (microtime (true) - START, 3)?>s -->
115  
-</body>
  119
+</body>
13  themes/greyscale/theme.css
@@ -26,7 +26,8 @@ html				{font: 16px/20px Corbel, "URW Gothic L", "Liberation Sans", "Trebuchet M
26 26
 
27 27
 
28 28
 /* page centering / width */
29  
-#mast nav, section, #mods	{width: 80%; max-width: 1024px;}
  29
+#mast nav, section, #mods,
  30
+ #rights			{width: 80%; max-width: 1024px;}
30 31
 
31 32
 h1				{margin: 0; padding: 20px 0 20px 60px;
32 33
 				 font-weight: bold; font-size: 22px; line-height: 20px; color: #f7f6f7;
@@ -107,6 +108,9 @@ input[type=search]:focus	{outline: none;}
107 108
 
108 109
 #go				{position: relative; margin-left: -20px; top: -20px;}
109 110
 
  111
+#rights				{margin: 0 auto; text-align: center; color: #888;}
  112
+#rights a			{color: #666;}
  113
+
110 114
 
111 115
 /* index page
112 116
    ====================================================================================================================== */
@@ -224,9 +228,9 @@ input, textarea			{font: 16px/20px Corbel, "Liberation Sans", "Trebuchet MS", sa
224 228
 label				{display: block; height: 40px; padding: 0 20px; line-height: 40px; color: #222;}
225 229
 
226 230
 form p				{padding: 0; color: #888;}
227  
-#ok, #error, #markup		{padding: 20px !important;}
  231
+#ok, #error, #markup		{padding: 20px 20px 0 !important;}
228 232
 #error				{color: #d11;}
229  
-#markup				{padding-top: 0 !important;}
  233
+
230 234
 
231 235
 input[type=text],
232 236
  input[type=password], textarea	{-webkit-box-shadow: inset 0 5px 5px -6px black;
@@ -312,6 +316,9 @@ footer				{position: absolute; height: 60px; margin: 20px 0 0; padding: 0 0 20px
312 316
 footer p			{margin: 0 auto 0 10%; padding-left: 20px; font-size: .9em; color: #f7f6f7;}
313 317
 footer p a			{color: #888;}
314 318
 
  319
+p#login				{margin: -40px 10% 0 auto; padding-right: 20px; text-align: right;}
  320
+p#login a			{text-transform: uppercase;}
  321
+
315 322
 
316 323
 /* ======================================================================================================================
317 324
    mobile / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / /
103  themes/greyscale/thread.inc.php
@@ -44,7 +44,9 @@
44 44
 	--></form>
45 45
 	
46 46
 	<nav><p>
47  
-		<?php if (!$HEADER['LOCKED']): ?><a id="add" href="#reply">Reply</a><?php endif;?>
  47
+<?php if (CAN_REPLY): ?>
  48
+		<a id="add" href="#reply">Reply</a>
  49
+<?php endif;?>
48 50
 		<a id="rss" href="<?php echo $HEADER['RSS']?>">RSS</a>
49 51
 	</p><p>
50 52
 		<a id="index" href="<?php echo FORUM_PATH?>">Index</a><?php if (PATH): ?> » <a href="<?php echo PATH_URL?>"><?php echo PATH?></a><?php endif; ?>
@@ -56,7 +58,7 @@
56 58
 	
57 59
 	<article class="op<?php echo $POST['MOD'] ? ' mod' : ''?>">
58 60
 		<header>
59  
-<?php if (!$HEADER['LOCKED']): ?>
  61
+<?php if (CAN_REPLY): ?>
60 62
 			<a class="ui append" rel="noindex nofollow" href="<?php echo $POST['APPEND_URL']?>">append</a>
61 63
 			<a class="ui delete" rel="noindex nofollow" href="<?php echo $POST['DELETE_URL']?>">delete</a>
62 64
 <?php endif; ?>
@@ -68,6 +70,16 @@
68 70
 	</article>
69 71
 </section>
70 72
 
  73
+<?php if (FORUM_LOCK == 'posts'): ?>
  74
+<p id="rights">
  75
+	Only <a href="#mods">moderators or members</a> can reply to this thread.
  76
+</p>
  77
+<?php elseif (FORUM_LOCK == 'private'): ?>
  78
+<p id="rights">
  79
+	Only <a href="#mods">moderators or members</a> can access and reply to this thread.
  80
+</p>
  81
+<?php endif;?>
  82
+
71 83
 <?php if (isset ($POSTS)): ?>
72 84
 <section id="replies">
73 85
 	<h1>Replies</h1>
@@ -76,10 +88,17 @@
76 88
 <?php foreach ($POSTS as $POST): ?>
77 89
 	<article id="<?php echo $POST['ID']?>" class="<?php echo implode(' ',array_filter(array($POST['DELETED'],$POST['OP'],$POST['MOD'])))?>">
78 90
 		<header>
79  
-<?php if (!$HEADER['LOCKED']): ?>
80  
-			<?php if (!$POST['DELETED']): ?><a class="ui append" rel="noindex nofollow" href="<?php echo $POST['APPEND_URL']?>">append</a>
81  
-			<a class="ui delete" rel="noindex nofollow" href="<?php echo $POST['DELETE_URL']?>">delete</a><?php endif;?>
82  
-<?php endif; ?>
  91
+<?php //visibility of the append/delete links:
  92
+      if ($POST['CAN_ACTION']):
  93
+      //append link not available when the post has been deleted
  94
+      if (!$POST['DELETED']): ?>
  95
+			<a class="ui append" rel="noindex nofollow" href="<?php echo $POST['APPEND_URL']?>">append</a>
  96
+<?php endif;
  97
+      //delete link not available when the post has been deleted, except to mods
  98
+      if (!$POST['DELETED'] || CAN_MOD): ?>
  99
+			<a class="ui delete" rel="noindex nofollow" href="<?php echo $POST['DELETE_URL']?>">delete</a>
  100
+<?php endif;
  101
+      endif;?>
83 102
 			<time datetime="<?php echo $POST['DATETIME']?>" pubdate><?php echo $POST['TIME']?></time>
84 103
 			<a href="?page=<?php echo PAGE?>#<?php echo $POST['ID']?>">#<?php echo $POST['NO']?>.</a>
85 104
 			<b<?php echo $POST['MOD']?' class="mod"':''?>><?php echo $POST['AUTHOR']?></b>
@@ -92,14 +111,19 @@
92 111
 	<nav><ol class="pages"><?php echo $PAGES?></ol></nav>
93 112
 </section>
94 113
 <?php endif; ?>
  114
+<?php if (CAN_REPLY): ?>
95 115
 <!-- =================================================================================================================== -->
96  
-<?php if (!$HEADER['LOCKED']): ?>
97 116
 <section id="reply">
98 117
 	<h1>Reply</h1>
99 118
 	<form method="post" action="#reply" enctype="application/x-www-form-urlencoded;charset=utf-8" autocomplete="on">
100  
-<?php if (FORUM_ENABLED): ?>
101 119
 		<div id="rightcol">
102  
-		
  120
+<?php if (HTTP_AUTH): ?>
  121
+		<label for="user">You are signed in as:</label>
  122
+		<p id="puser">
  123
+			<input name="username" id="user" type="text" size="28" maxlength="<?php echo SIZE_NAME ?>"
  124
+			       disabled value="<?php echo HTTP_AUTH_UN ?>" />
  125
+		</p>
  126
+<?php else: ?>
103 127
 		<p id="puser">
104 128
 			<label for="user">Name:</label>
105 129
 			<input name="username" id="user" type="text" size="28" tabindex="2"
@@ -116,12 +140,17 @@
116 140
 			       required autocomplete="off" />
117 141
 			(Leave this as-is, it’s a trap!)
118 142
 		</p>
  143
+<?php endif; ?>
119 144
 <?php switch ($FORM['ERROR']):
120 145
 	case ERROR_NONE:
121  
-	if (FORUM_NEWBIES): ?>
122  
-		<p id="ok">There is no need to “register”, just enter the same name + password of your choice every time.</p>
123  
-<?php	else :?>
  146
+	//if signed in, there's no password field
  147
+	if (HTTP_AUTH): ?>
  148
+		<p id="ok">(Quit your browser or clear the browser cache to sign out.)</p>
  149
+<?php	//if new users are not allowed
  150
+	elseif (!FORUM_NEWBIES): ?>
124 151
 		<p id="error">Only registered users can post.<br />No new registrations are allowed.</p>
  152
+<?php	else: ?>
  153
+		<p id="ok">There is no need to “register”, just enter the same name + password of your choice every time.</p>
125 154
 <?php	endif;
126 155
 	break;
127 156
 	case ERROR_NAME: ?>
@@ -157,36 +186,45 @@
157 186
 			<input id="submit" name="submit" type="image" src="<?php echo FORUM_PATH?>themes/<?php echo FORUM_THEME?>/icons/submit.png"
158 187
 			       width="40" height="40" tabindex="4" value="&gt;" />
159 188
 		</label></p>
160  
-<?php else: ?>
161  
-		<p id="error">Sorry, posting is currently disabled.</p>
162  
-		<p id="psubmit">
163  
-<?php endif; ?>
164 189
 	</form>
165 190
 </section>
166 191
 <?php endif; ?>
167 192
 <!-- =================================================================================================================== -->
168 193
 <div id="mods">
169  
-<p id="admin">
170  
-	<a id="<?php echo $HEADER['LOCKED'] ? 'unlock' : 'lock';?>" href="<?php echo $HEADER['LOCK_URL'];?>" rel="noindex nofollow"><?php echo $HEADER['LOCKED'] ? 'Unlock' : 'Lock';?></a>
171  
-</p>
172  
-<?php if (!empty ($MODS['LOCAL'])): ?>
173  
-<p>
174  
-	Moderators for this sub-forum:
175  
-	<b class="mod"><?php echo implode ('</b>, <b class="mod">', array_map ('safeHTML', $MODS['LOCAL']))?></b>
176  
-</p>
177  
-<?php endif; ?>
178  
-<?php if (!empty ($MODS['GLOBAL'])): ?>
179  
-<p>
180  
-	Your friendly neighbourhood moderators:
181  
-	<b class="mod"><?php echo implode ('</b>, <b class="mod">', array_map ('safeHTML', $MODS['GLOBAL']))?></b>
182  
-</p>
  194
+<?php if (CAN_MOD): ?>
  195
+	<p id="admin">
  196
+		<a id="<?php echo $HEADER['LOCKED'] ? 'unlock' : 'lock';?>" href="<?php echo $HEADER['LOCK_URL'];?>" rel="noindex nofollow"><?php echo $HEADER['LOCKED'] ? 'Unlock' : 'Lock';?></a>
  197
+	</p>
  198
+<?php endif;
  199
+      if (!empty ($MODS['LOCAL'])): ?>
  200
+	<p>
  201
+		Moderators for this sub-forum:
  202
+		<b class="mod"><?php echo implode ('</b>, <b class="mod">', array_map ('safeHTML', $MODS['LOCAL']))?></b>
  203
+	</p>
  204
+<?php endif;
  205
+      if (!empty ($MODS['GLOBAL'])): ?>
  206
+	<p>
  207
+		Your friendly neighbourhood moderators:
  208
+		<b class="mod"><?php echo implode ('</b>, <b class="mod">', array_map ('safeHTML', $MODS['GLOBAL']))?></b>
  209
+	</p>
  210
+<?php endif;
  211
+      if (!empty ($MEMBERS)): ?>
  212
+	<p>
  213
+		Members of this forum:
  214
+		<b><?php echo implode ('</b>, <b>', array_map ('safeHTML', $MEMBERS))?></b>
  215
+	</p>
183 216
 <?php endif; ?>
184 217
 </div>
185 218
 <footer><p>
186 219
 	Powered by <a href="http://camendesign.com/nononsense_forum">NoNonsense Forum</a><br />
187 220
 	© Kroc Camen of <a href="http://camendesign.com">Camen Design</a>
  221
+</p><p id="login">
  222
+<?php if (HTTP_AUTH): ?>
  223
+	Signed in as: <b><?php echo safeHTML (HTTP_AUTH_UN); ?></b>
  224
+<?php else: ?>
  225
+	<a href="?login">Sign in</a>
  226
+<?php endif; ?>
188 227
 </p></footer>
189  
-<div id="grid"></div>
190 228
 <script>
191 229
 //in iOS tapping a label doesn't click the related input element, we'll add this back in using JavaScript
192 230
 if (document.getElementsByTagName !== undefined) {
@@ -195,5 +233,4 @@
195 233
 	for (i=0; i<labels.length; i++) if (labels[i].getAttribute ("for")) labels[i].onclick = function (){}
196 234
 }
197 235
 </script>
198  
-<!-- page generated in: <?php echo round (microtime (true) - START, 3)?>s -->
199  
-</body>
  236
+</body>
42  thread.php
@@ -7,16 +7,28 @@
7 7
 
8 8
 require_once './shared.php';
9 9
 
  10
+//get the post message, the other fields (name / pass) are retrieved automatically in 'shared.php'
  11
+define ('TEXT', safeGet (@$_POST['text'], SIZE_TEXT));
  12
+
10 13
 //which thread to show
11 14
 $FILE = (preg_match ('/^[^.\/]+$/', @$_GET['file']) ? $_GET['file'] : '') or die ('Malformed request');
  15
+//load the thread (have to read lock status from the file)
  16
+$xml = simplexml_load_file ("$FILE.rss") or die ('Malformed XML');
12 17
 
13  
-//get the post message, the other fields (name / pass) are retrieved automatically in 'shared.php'
14  
-define ('TEXT', safeGet (@$_POST['text'], SIZE_TEXT));
  18
+//access rights for the current user
  19
+define ('CAN_REPLY', FORUM_ENABLED && (
  20
+	//- if the thread is unlocked and the forum is either unlocked or thread-locked (anybody can reply)
  21
+	(!(bool) $xml->channel->xpath ("category[text()='locked']") && (!FORUM_LOCK || FORUM_LOCK == 'threads')) ||
  22
+	//- if the thread is locked, but you are a moderator (signed in)
  23
+	((bool) $xml->channel->xpath ("category[text()='locked']") && CAN_MOD) ||
  24
+	//- if the forum is post-locked, but you are a moderator (signed in) or member
  25
+	(FORUM_LOCK == 'posts' && (CAN_MOD || isMember (NAME)))
  26
+));
15 27
 
16 28
 /* ====================================================================================================================== */
17 29
 
18 30
 //was the submit button clicked? (and is the info valid?)
19  
-if (FORUM_ENABLED && NAME && PASS && AUTH && TEXT && @$_POST['email'] == 'example@abc.com') {
  31
+if (CAN_REPLY && AUTH && TEXT && @$_POST['email'] == 'example@abc.com') {
20 32
 	//get a write lock on the file so that between now and saving, no other posts could slip in
21 33
 	$f = fopen ("$FILE.rss", 'c'); flock ($f, LOCK_EX);
22 34
 	
@@ -66,9 +78,6 @@
66 78
 
67 79
 /* ====================================================================================================================== */
68 80
 
69  
-//load the thread
70  
-$xml = simplexml_load_file ("$FILE.rss") or die ('Malformed XML');
71  
-
72 81
 //info for the site header
73 82
 $HEADER = array (
74 83
 	'TITLE'		=> safeHTML ($xml->channel->title),
@@ -102,7 +111,7 @@
102 111
 
103 112
 /* replies
104 113
    ---------------------------------------------------------------------------------------------------------------------- */
105  
-//determine the page number (for threads the page number can be given as "last")
  114
+//determine the page number (for threads, the page number can be given as "last")
106 115
 define ('PAGE',
107 116
 	@$_GET['page'] == 'last'
108 117
 	? ceil (count ($thread) / FORUM_POSTS)
@@ -112,8 +121,8 @@
112 121
 if (count ($thread)) {
113 122
 	//sort the other way around
114 123
 	//<stackoverflow.com/questions/2119686/sorting-an-array-of-simplexml-objects/2120569#2120569>
115  
-	foreach ($thread as &$node) $sort_proxy[] = strtotime ($node->pubDate);
116  
-	array_multisort ($sort_proxy, SORT_ASC, $thread);
  124
+	foreach ($thread as &$node) $sort[] = strtotime ($node->pubDate);
  125
+	array_multisort ($sort, SORT_ASC, $thread);
117 126
 	
118 127
 	//paging
119 128
 	$PAGES  = pageList (PAGE, ceil (count ($thread) / FORUM_POSTS));
@@ -127,6 +136,19 @@
127 136
 		'TIME'		=> date (DATE_FORMAT, strtotime ($post->pubDate)),	//human readable time
128 137
 		'TEXT'		=> $post->description,
129 138
 		'DELETED'	=> (bool) $post->xpath ("category[text()='deleted']") ? 'deleted' : '',
  139
+		//if the current user in the curent forum can append/delete the current post:
  140
+		'CAN_ACTION'	=> CAN_REPLY && (
  141
+			//moderators can always see append/delete links on all posts
  142
+			CAN_MOD ||
  143
+			//if you are not signed in, all append/delete links are shown (if forum/thread locking is off)
  144
+			//if you are signed in, then only links on posts with your name will show
  145
+			!HTTP_AUTH ||
  146
+			//if this post is the by the owner (they can append/delete to their own posts)
  147
+			(strtolower (NAME) == strtolower ($post->author) && (
  148
+				//if the forum is post-locked, they must be a member to append/delete their own posts
  149
+				(!FORUM_LOCK || FORUM_LOCK == 'threads') || isMember (NAME)
  150
+			))
  151
+		),
130 152
 		'DELETE_URL'	=> FORUM_PATH . 'action.php?delete&amp;path='.safeURL (PATH)."&amp;file=$FILE&amp;id="
131 153
 				  .substr (strstr ($post->link, '#'), 1),
132 154
 		'APPEND_URL'	=> FORUM_PATH . 'action.php?append&amp;path='.safeURL (PATH)."&amp;file=$FILE&amp;id="
@@ -140,7 +162,7 @@
140 162
 
141 163
 /* reply form
142 164
    ---------------------------------------------------------------------------------------------------------------------- */
143  
-if (FORUM_ENABLED) $FORM = array (
  165
+if (CAN_REPLY) $FORM = array (
144 166
 	'NAME'	=> safeString (NAME),
145 167
 	'PASS'	=> safeString (PASS),
146 168
 	'TEXT'	=> safeString (TEXT),

0 notes on commit 0bee588

Please sign in to comment.
Something went wrong with that request. Please try again.