Bug #24342 » 16749_v2.patch

Administrator Admin, 2010-12-16 14:18

View differences:

t3lib/class.t3lib_abstract_lock.php (revision 0)
1
<?php
2
/***************************************************************
3
 *  Copyright notice
4
 *
5
 *  (c) 2008-2010 Michael Stucki (michael@typo3.org)
6
 *  All rights reserved
7
 *
8
 *  This script is part of the TYPO3 project. The TYPO3 project is
9
 *  free software; you can redistribute it and/or modify
10
 *  it under the terms of the GNU General Public License as published by
11
 *  the Free Software Foundation; either version 2 of the License, or
12
 *  (at your option) any later version.
13
 *
14
 *  The GNU General Public License can be found at
15
 *  http://www.gnu.org/copyleft/gpl.html.
16
 *  A copy is found in the textfile GPL.txt and important notices to the license
17
 *  from the author is found in LICENSE.txt distributed with these scripts.
18
 *
19
 *
20
 *  This script is distributed in the hope that it will be useful,
21
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
22
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23
 *  GNU General Public License for more details.
24
 *
25
 *  This copyright notice MUST APPEAR in all copies of the script!
26
 ***************************************************************/
27
/**
28
 * Class for providing locking features in TYPO3
29
 *
30
 * $Id: class.t3lib_lock.php 9758 2010-12-05 11:25:36Z stephenking $
31
 *
32
 * @author	Michael Stucki <michael@typo3.org>
33
 */
34

  
35

  
36
/**
37
 * TYPO3 locking class
38
 * This class provides an abstract layer to various locking features for TYPO3
39
 *
40
 * It is intended to blocks requests until some data has been generated.
41
 * This is especially useful if two clients are requesting the same website short after each other. While the request of client 1 triggers building and caching of the website, client 2 will be waiting at this lock.
42
 *
43
 * @author	Michael Stucki <michael@typo3.org>
44
 * @package TYPO3
45
 * @subpackage t3lib
46
 * @see	class.t3lib_tstemplate.php, class.tslib_fe.php
47
 */
48
class t3lib_abstract_lock {
49
	protected $method;
50
	protected $id; // Identifier used for this lock
51
	protected $resource; // Resource used for this lock (can be a file or a semaphore resource)
52
	protected $filepointer;
53
	protected $isAcquired = FALSE;
54
	protected $destruct=FALSE;  // destroy all resources on destruct
55

  
56
	protected $loops = 150; // Number of times a locked resource is tried to be acquired. This is only used by manual locks like the "simple" method.
57
	protected $step = 200; // Milliseconds after lock acquire is retried. $loops * $step results in the maximum delay of a lock. Only used by manual locks like the "simple" method.
58

  
59

  
60
	/**
61
	 * Constructor:
62
	 * initializes locking, check input parameters and set variables accordingly.
63
	 *
64
	 * @param	string		ID to identify this lock in the system
65
	 * @param	string		Define which locking method to use. Defaults to "simple".
66
	 * @param	integer		Number of times a locked resource is tried to be acquired. This is only used by manual locks like the "simple" method.
67
	 * @param	integer		Milliseconds after lock acquire is retried. $loops * $step results in the maximum delay of a lock. Only used by manual locks like the "simple" method.
68
	 * @return	boolean		Returns true unless something went wrong
69
	 */
70
	public function __construct($id, $method = '', $loops = 0, $step = 0) {
71

  
72
			// Input checks
73
		$id = (string) $id; // Force ID to be string
74
		if (intval($loops)) {
75
			$this->loops = intval($loops);
76
		}
77
		if (intval($step)) {
78
			$this->step = intval($step);
79
		}
80

  
81
			// Detect locking method
82
		if (in_array($method, array('disable', 'simple', 'flock', 'semaphore'))) {
83
			$this->method = $method;
84
		} else {
85
			throw new Exception('No such method "' . $method . '"');
86
		}
87

  
88
		$success = FALSE;
89
		switch ($this->method) {
90
			case 'simple':
91
			case 'flock':
92
				$path = PATH_site . 'typo3temp/locks/';
93
				if (!is_dir($path)) {
94
					t3lib_div::mkdir($path);
95
				}
96
				$this->id = md5($id);
97
				$this->resource = $path . $this->id;
98
				$success = TRUE;
99
			break;
100
			case 'semaphore':
101
				$this->id = abs(crc32($id));
102
				if (($this->resource = sem_get($this->id, 1)) == TRUE) {
103
					$success = TRUE;
104
				}
105
			break;
106
			case 'disable':
107
				return FALSE;
108
			break;
109
		}
110

  
111
		return $success;
112
	}
113

  
114
	/**
115
	 * Destructor:
116
	 * Releases lock automatically when instance is destroyed.
117
	 *
118
	 * @return	void
119
	 */
120
	function __destruct() {
121
		$this->destruct=TRUE;
122
		$this->release();
123
	}
124

  
125
	/**
126
	 * Acquire a lock and return when successful. If the lock is already open, the client will be
127
	 *
128
	 * It is important to know that the lock will be acquired in any case, even if the request was blocked first. Therefore, the lock needs to be released in every situation.
129
	 *
130
	 * @return	boolean		Returns true if lock could be acquired without waiting, false otherwise.
131
	 */
132
	public function acquire() {
133

  
134
		$this->isAcquired = FALSE;
135
		return FALSE;
136
	}
137

  
138
	/**
139
	 * Release the lock
140
	 *
141
	 * @return	boolean		Returns TRUE on success or FALSE on failure
142
	 */
143
	public function release() {
144
		return TRUE;
145
	}
146

  
147
	/**
148
	 * Return the locking method which is currently used
149
	 *
150
	 * @return	string		Locking method
151
	 */
152
	public function getMethod() {
153
		return $this->method;
154
	}
155

  
156
	/**
157
	 * Return the ID which is currently used
158
	 *
159
	 * @return	string		Locking ID
160
	 */
161
	public function getId() {
162
		return $this->id;
163
	}
164

  
165
	/**
166
	 * Return the resource which is currently used.
167
	 * Depending on the locking method this can be a filename or a semaphore resource.
168
	 *
169
	 * @return	mixed		Locking resource (filename as string or semaphore as resource)
170
	 */
171
	public function getResource() {
172
		return $this->resource;
173
	}
174

  
175
	/**
176
	 * Return the status of a lock
177
	 *
178
	 * @return	string		Returns TRUE if lock is acquired, FALSE otherwise
179
	 */
180
	public function getLockStatus() {
181
		return $this->isAcquired;
182
	}
183

  
184
	/**
185
	 * Adds a common log entry for this locking API using t3lib_div::sysLog().
186
	 * Example: 25-02-08 17:58 - cms: Locking [simple::0aeafd2a67a6bb8b9543fb9ea25ecbe2]: Acquired
187
	 *
188
	 * @param	string		$message: The message to be logged
189
	 * @param	integer		$severity: Severity - 0 is info (default), 1 is notice, 2 is warning, 3 is error, 4 is fatal error
190
	 * @return	void
191
	 */
192
	public function sysLog($message, $severity = 0) {
193
		t3lib_div::sysLog('Locking [' . $this->method . '::' . $this->id . ']: ' . trim($message), 'cms', $severity);
194
	}
195
}
196
	
197

  
198

  
199
if (defined('TYPO3_MODE') && isset($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_abstract_lock.php'])) {
200
	include_once($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_abstract_lock.php']);
201
}
202
?>
t3lib/class.t3lib_lock.php (working copy)
45 45
 * @subpackage t3lib
46 46
 * @see	class.t3lib_tstemplate.php, class.tslib_fe.php
47 47
 */
48
class t3lib_lock {
49
	protected $method;
50
	protected $id; // Identifier used for this lock
51
	protected $resource; // Resource used for this lock (can be a file or a semaphore resource)
52
	protected $filepointer;
53
	protected $isAcquired = FALSE;
54 48

  
55
	protected $loops = 150; // Number of times a locked resource is tried to be acquired. This is only used by manual locks like the "simple" method.
56
	protected $step = 200; // Milliseconds after lock acquire is retried. $loops * $step results in the maximum delay of a lock. Only used by manual locks like the "simple" method.
49
class t3lib_lock extends t3lib_abstract_lock {
57 50

  
58

  
51
	
59 52
	/**
60 53
	 * Constructor:
61 54
	 * initializes locking, check input parameters and set variables accordingly.
......
67 60
	 * @return	boolean		Returns true unless something went wrong
68 61
	 */
69 62
	public function __construct($id, $method = '', $loops = 0, $step = 0) {
70

  
71
			// Input checks
72
		$id = (string) $id; // Force ID to be string
73
		if (intval($loops)) {
74
			$this->loops = intval($loops);
63
		parent::__construct($id,$method,$loops,$step);
64
		$this->initLockLock($method,$loops,$step);
65
	}
66
	
67
	public function initLockLock($method,$loops,$step) {
68
		if (!$GLOBALS['lockLock'] || !($GLOBALS['lockLock'] instanceof t3lib_lock_static)) {
69
			$GLOBALS['lockLock']=t3lib_div::makeInstance('t3lib_lock_static','lockLock',$method,$loops,$step);
75 70
		}
76
		if (intval($step)) {
77
			$this->step = intval($step);
78
		}
79

  
80
			// Detect locking method
81
		if (in_array($method, array('disable', 'simple', 'flock', 'semaphore'))) {
82
			$this->method = $method;
83
		} else {
84
			throw new Exception('No such method "' . $method . '"');
85
		}
86

  
87
		$success = FALSE;
88
		switch ($this->method) {
89
			case 'simple':
90
			case 'flock':
91
				$path = PATH_site . 'typo3temp/locks/';
92
				if (!is_dir($path)) {
93
					t3lib_div::mkdir($path);
94
				}
95
				$this->id = md5($id);
96
				$this->resource = $path . $this->id;
97
				$success = TRUE;
98
			break;
99
			case 'semaphore':
100
				$this->id = abs(crc32($id));
101
				if (($this->resource = sem_get($this->id, 1)) == TRUE) {
102
					$success = TRUE;
103
				}
104
			break;
105
			case 'disable':
106
				return FALSE;
107
			break;
108
		}
109

  
110
		return $success;
71
	
111 72
	}
112

  
113 73
	/**
114
	 * Destructor:
115
	 * Releases lock automatically when instance is destroyed.
116
	 *
117
	 * @return	void
118
	 */
119
	function __destruct() {
120
		$this->release();
121
	}
122

  
123
	/**
124 74
	 * Acquire a lock and return when successful. If the lock is already open, the client will be
125 75
	 *
126 76
	 * It is important to know that the lock will be acquired in any case, even if the request was blocked first. Therefore, the lock needs to be released in every situation.
......
137 87
					$this->sysLog('Waiting for a different process to release the lock');
138 88
					$maxExecutionTime = ini_get('max_execution_time');
139 89
					$maxAge = time() - ($maxExecutionTime ? $maxExecutionTime : 120);
140
					if (@filectime($this->resource) < $maxAge) {
141
						@unlink($this->resource);
142
						$this->sysLog('Unlink stale lockfile');
90
					if ($GLOBALS['lockLock']->acquire() || $GLOBALS['lockLock']->getLockStatus()){
91
						if (@filectime($this->resource) < $maxAge) {
92
							@unlink($this->resource);
93
							$this->sysLog('Unlink stale lockfile');
94
						}
143 95
					}
96
					$GLOBALS['lockLock']->release();
144 97
				}
145 98

  
146 99
				$isAcquired = FALSE;
......
148 101
					$filepointer = @fopen($this->resource, 'x');
149 102
					if ($filepointer !== FALSE) {
150 103
						fclose($filepointer);
151
						$this->sysLog('Lock aquired');
104
						$this->sysLog('Lock acquired');
152 105
						$noWait = ($i === 0);
153 106
						$isAcquired = TRUE;
154 107
						break;
......
174 127
				}
175 128
			break;
176 129
			case 'semaphore':
130
				$this->sysLog('Acquire semaphore ' . $this->id );
177 131
				if (sem_acquire($this->resource)) {
178 132
						// Unfortunately it seems not possible to find out if the request was blocked, so we return FALSE in any case to make sure the operation is tried again.
179 133
					$noWait = FALSE;
......
195 149
	 * @return	boolean		Returns TRUE on success or FALSE on failure
196 150
	 */
197 151
	public function release() {
198
		if (!$this->isAcquired) {
152
		if (!$this->isAcquired&& !$this->destruct) {
199 153
			return TRUE;
200 154
		}
201 155

  
202 156
		$success = TRUE;
203
		switch ($this->method) {
204
			case 'simple':
205
				if (unlink($this->resource) == FALSE) {
157
		if ($GLOBALS['lockLock']->acquire() || $GLOBALS['lockLock']->getLockStatus()){
158
			switch ($this->method) {
159
				case 'simple':
160
					if (unlink($this->resource) == FALSE) {
161
						$success = FALSE;
162
					}
163
				break;
164
				case 'flock':
165
					if (flock($this->filepointer, LOCK_UN) == FALSE) {
166
						$success = FALSE;
167
					}
168
					fclose($this->filepointer);
169
					unlink($this->resource);
170
				break;
171
				case 'semaphore':
172
					if (@sem_release($this->resource)) {
173
						sem_remove($this->resource);
174
					} else {
175
						$success = FALSE;
176
					}
177
				break;
178
				case 'disable':
206 179
					$success = FALSE;
207
				}
208
			break;
209
			case 'flock':
210
				if (flock($this->filepointer, LOCK_UN) == FALSE) {
211
					$success = FALSE;
212
				}
213
				fclose($this->filepointer);
214
				unlink($this->resource);
215
			break;
216
			case 'semaphore':
217
				if (@sem_release($this->resource)) {
218
					sem_remove($this->resource);
219
				} else {
220
					$success = FALSE;
221
				}
222
			break;
223
			case 'disable':
224
				$success = FALSE;
225
			break;
180
				break;
181
			}
226 182
		}
227

  
183
		$GLOBALS['lockLock']->release();
228 184
		$this->isAcquired = FALSE;
229 185
		return $success;
230 186
	}
231 187

  
232
	/**
233
	 * Return the locking method which is currently used
234
	 *
235
	 * @return	string		Locking method
236
	 */
237
	public function getMethod() {
238
		return $this->method;
239
	}
240

  
241
	/**
242
	 * Return the ID which is currently used
243
	 *
244
	 * @return	string		Locking ID
245
	 */
246
	public function getId() {
247
		return $this->id;
248
	}
249

  
250
	/**
251
	 * Return the resource which is currently used.
252
	 * Depending on the locking method this can be a filename or a semaphore resource.
253
	 *
254
	 * @return	mixed		Locking resource (filename as string or semaphore as resource)
255
	 */
256
	public function getResource() {
257
		return $this->resource;
258
	}
259

  
260
	/**
261
	 * Return the status of a lock
262
	 *
263
	 * @return	string		Returns TRUE if lock is acquired, FALSE otherwise
264
	 */
265
	public function getLockStatus() {
266
		return $this->isAcquired;
267
	}
268

  
269
	/**
270
	 * Adds a common log entry for this locking API using t3lib_div::sysLog().
271
	 * Example: 25-02-08 17:58 - cms: Locking [simple::0aeafd2a67a6bb8b9543fb9ea25ecbe2]: Acquired
272
	 *
273
	 * @param	string		$message: The message to be logged
274
	 * @param	integer		$severity: Severity - 0 is info (default), 1 is notice, 2 is warning, 3 is error, 4 is fatal error
275
	 * @return	void
276
	 */
277
	public function sysLog($message, $severity = 0) {
278
		t3lib_div::sysLog('Locking [' . $this->method . '::' . $this->id . ']: ' . trim($message), 'cms', $severity);
279
	}
280 188
}
281 189

  
282 190

  
t3lib/class.t3lib_lock_static.php (revision 0)
1
<?php
2
/***************************************************************
3
 *  Copyright notice
4
 *
5
 *  (c) 2008-2010 Michael Stucki (michael@typo3.org)
6
 *  All rights reserved
7
 *
8
 *  This script is part of the TYPO3 project. The TYPO3 project is
9
 *  free software; you can redistribute it and/or modify
10
 *  it under the terms of the GNU General Public License as published by
11
 *  the Free Software Foundation; either version 2 of the License, or
12
 *  (at your option) any later version.
13
 *
14
 *  The GNU General Public License can be found at
15
 *  http://www.gnu.org/copyleft/gpl.html.
16
 *  A copy is found in the textfile GPL.txt and important notices to the license
17
 *  from the author is found in LICENSE.txt distributed with these scripts.
18
 *
19
 *
20
 *  This script is distributed in the hope that it will be useful,
21
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
22
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23
 *  GNU General Public License for more details.
24
 *
25
 *  This copyright notice MUST APPEAR in all copies of the script!
26
 ***************************************************************/
27
/**
28
 * Class for providing locking features in TYPO3
29
 *
30
 * $Id: class.t3lib_lock.php 9758 2010-12-05 11:25:36Z stephenking $
31
 *
32
 * @author	Michael Stucki <michael@typo3.org>
33
 */
34

  
35

  
36

  
37
class t3lib_lock_static extends t3lib_abstract_lock {
38

  
39
	/**
40
	 * Constructor:
41
	 * initializes locking, check input parameters and set variables accordingly.
42
	 *
43
	 * @param	string		ID to identify this lock in the system
44
	 * @param	string		Define which locking method to use. Defaults to "simple".
45
	 * @param	integer		Number of times a locked resource is tried to be acquired. This is only used by manual locks like the "simple" method.
46
	 * @param	integer		Milliseconds after lock acquire is retried. $loops * $step results in the maximum delay of a lock. Only used by manual locks like the "simple" method.
47
	 * @return	boolean		Returns true unless something went wrong
48
	 */
49
	public function __construct($id, $method = '', $loops = 0, $step = 0) {
50
		$res=parent::__construct($id,$method,$loops,$step);
51
		parent::sysLog("Static semaphore " . $this->id);
52
		return $res;
53
	}
54
	/**
55
	 * Acquire a lock and return when successful. If the lock is already open, the client will be
56
	 *
57
	 * It is important to know that the lock will be acquired in any case, even if the request was blocked first. Therefore, the lock needs to be released in every situation.
58
	 *
59
	 * @return	boolean		Returns true if lock could be acquired without waiting, false otherwise.
60
	 */
61
	public function acquire() {
62
		$noWait = TRUE; // Default is TRUE, which means continue without caring for other clients. In the case of TYPO3s cache management, this has no negative effect except some resource overhead.
63
		$isAcquired = TRUE;
64

  
65
		switch ($this->method) {
66
			case 'simple':
67
				if (is_file($this->resource)) {
68
					$this->sysLog('Waiting for a different process to release the lock');
69
					$maxExecutionTime = ini_get('max_execution_time');
70
					$maxAge = time() - 3*($maxExecutionTime ? $maxExecutionTime : 120);
71
					if (@filectime($this->resource) < $maxAge) {
72
						@unlink($this->resource);
73
						$this->sysLog('Unlink stale lockfile');
74
					}
75
				}
76

  
77
				$isAcquired = FALSE;
78
				for ($i = 0; $i < $this->loops; $i++) {
79
					$filepointer = @fopen($this->resource, 'x');
80
					if ($filepointer !== FALSE) {
81
						fclose($filepointer);
82
						$this->sysLog('Lock acquired');
83
						$noWait = ($i === 0);
84
						$isAcquired = TRUE;
85
						break;
86
					}
87
					usleep($this->step * 1000);
88
				}
89

  
90
				if (!$isAcquired) {
91
					throw new Exception('Lock file could not be created');
92
				}
93
			break;
94
			case 'flock':
95
				if (($this->filepointer = fopen($this->resource, 'w+')) == FALSE) {
96
					throw new Exception('Lock file could not be opened');
97
				}
98

  
99
				if (flock($this->filepointer, LOCK_EX | LOCK_NB) == TRUE) { // Lock without blocking
100
					$noWait = TRUE;
101
				} elseif (flock($this->filepointer, LOCK_EX) == TRUE) { // Lock with blocking (waiting for similar locks to become released)
102
					$noWait = FALSE;
103
				} else {
104
					throw new Exception('Could not lock file "' . $this->resource . '"');
105
				}
106
			break;
107
			case 'semaphore':
108
				$this->sysLog('Static semaphore ' . $this->id );
109
				if (sem_acquire($this->resource)) {
110
						$this->sysLog('Static semaphore ' . $this->id );
111
						// Unfortunately it seems not possible to find out if the request was blocked, so we return FALSE in any case to make sure the operation is tried again.
112
					$noWait = FALSE;
113
				}
114
			break;
115
			case 'disable':
116
				$noWait = FALSE;
117
				$isAcquired = FALSE;
118
			break;
119
		}
120

  
121
		$this->isAcquired = $isAcquired;
122
		return $noWait;
123
	}
124

  
125
	/**
126
	 * Release the lock
127
	 *
128
	 * @return	boolean		Returns TRUE on success or FALSE on failure
129
	 */
130
	public function release() {
131
		$this->sysLog('Release static semaphore ' . $this->id );
132
		if (!$this->isAcquired&& !$this->destruct) {
133
			return TRUE;
134
		}
135

  
136
		$success = TRUE;
137
		switch ($this->method) {
138
			case 'simple':
139
				if (unlink($this->resource) == FALSE) {
140
					$success = FALSE;
141
				}
142
			break;
143
			case 'flock':
144
				if (flock($this->filepointer, LOCK_UN) == FALSE) {
145
					$success = FALSE;
146
				}
147
				fclose($this->filepointer);
148
			break;
149
			case 'semaphore':
150
				$this->sysLog('Release static semaphore ' . $this->id );
151
				if (@sem_release($this->resource)) {
152
				} else {
153
					$success = FALSE;
154
				}
155
			break;
156
			case 'disable':
157
				$success = FALSE;
158
			break;
159
		}
160

  
161
		$this->isAcquired = FALSE;
162
		return $success;
163
	}
164

  
165
}
166

  
167

  
168
if (defined('TYPO3_MODE') && isset($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_lock_static.php'])) {
169
	include_once($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_lock_static.php']);
170
}
171
?>
t3lib/core_autoload.php (working copy)
5 5

  
6 6
$t3libClasses = array(
7 7
	'gzip_encode' => PATH_t3lib . 'class.gzip_encode.php',
8
	't3lib_abstract_lock' => PATH_t3lib . 'class.t3lib_abstract_lock.php',
8 9
	't3lib_admin' => PATH_t3lib . 'class.t3lib_admin.php',
9 10
	't3lib_ajax' => PATH_t3lib . 'class.t3lib_ajax.php',
10 11
	't3lib_arraybrowser' => PATH_t3lib . 'class.t3lib_arraybrowser.php',
......
41 42
	't3lib_loaddbgroup' => PATH_t3lib . 'class.t3lib_loaddbgroup.php',
42 43
	't3lib_loadmodules' => PATH_t3lib . 'class.t3lib_loadmodules.php',
43 44
	't3lib_lock' => PATH_t3lib . 'class.t3lib_lock.php',
45
	't3lib_lock_static' => PATH_t3lib . 'class.t3lib_lock_static.php',
44 46
	't3lib_matchcondition' => PATH_t3lib . 'class.t3lib_matchcondition.php',
45 47
	't3lib_message_abstractmessage' => PATH_t3lib . 'message/class.t3lib_message_abstractmessage.php',
46 48
	't3lib_message_errorpagemessage' => PATH_t3lib . 'message/class.t3lib_message_errorpagemessage.php',
......
135 137
	't3lib_tceformsinlinehook' => PATH_t3lib . 'interfaces/interface.t3lib_tceformsinlinehook.php',
136 138
	't3lib_tcemain_checkmodifyaccesslisthook' => PATH_t3lib . 'interfaces/interface.t3lib_tcemain_checkmodifyaccesslisthook.php',
137 139
	't3lib_tcemain_processuploadhook' => PATH_t3lib . 'interfaces/interface.t3lib_tcemain_processuploadhook.php',
138
	't3lib_mail_mboxtransport' => PATH_t3lib . 'mail/class.t3lib_mail_mboxtransport.php', 
140
	't3lib_mail_mboxtransport' => PATH_t3lib . 'mail/class.t3lib_mail_mboxtransport.php',
139 141
	't3lib_mail_message' => PATH_t3lib . 'mail/class.t3lib_mail_message.php',
140 142
	't3lib_mail_mailer' => PATH_t3lib . 'mail/class.t3lib_mail_mailer.php',
141 143
	'tx_t3lib_mail_hooks' => PATH_t3lib . 'mail/class.tx_t3lib_mail_hooks.php',
(2-2/4)