Converted "foo" to 'foo' for abook_*.php
[squirrelmail.git] / functions / abook_local_file.php
CommitLineData
5100704d 1<?php
2
3 /**
4 ** abook_local_file.php
5 **
6 ** Backend for addressbook as a pipe separated file
7 **
8 ** An array with the following elements must be passed to
9 ** the class constructor (elements marked ? are optional):
10 **
11 ** filename => path to addressbook file
12 ** ? create => if true: file is created if it does not exist.
13 ** ? umask => umask set before opening file.
14 **
15 ** NOTE. This class should not be used directly. Use the
16 ** "AddressBook" class instead.
245a6892 17 **
18 ** $Id$
5100704d 19 **/
20
21 class abook_local_file extends addressbook_backend {
91be2362 22 var $btype = 'local';
23 var $bname = 'local_file';
5100704d 24
91be2362 25 var $filename = '';
5100704d 26 var $filehandle = 0;
27 var $create = false;
28 var $umask;
29
30 // ========================== Private =======================
31
32 // Constructor
33 function abook_local_file($param) {
91be2362 34 $this->sname = _('Personal address book');
5100704d 35 $this->umask = Umask();
36
37 if(is_array($param)) {
91be2362 38 if(empty($param['filename']))
39 return $this->set_error('Invalid parameters');
40 if(!is_string($param['filename']))
41 return $this->set_error($param['filename'] . ': '.
42 _('Not a file name'));
5100704d 43
91be2362 44 $this->filename = $param['filename'];
5100704d 45
91be2362 46 if($param['create'])
5100704d 47 $this->create = true;
91be2362 48 if(isset($param['umask']))
49 $this->umask = $param['umask'];
5100704d 50
91be2362 51 if(!empty($param['name']))
52 $this->sname = $param['name'];
d50a8c48 53
5100704d 54 $this->open(true);
55 } else {
91be2362 56 $this->set_error('Invalid argument to constructor');
5100704d 57 }
58 }
59
60 // Open the addressbook file and store the file pointer.
61 // Use $file as the file to open, or the class' own
62 // filename property. If $param is empty and file is
63 // open, do nothing.
64 function open($new = false) {
91be2362 65 $this->error = '';
5100704d 66 $file = $this->filename;
67 $create = $this->create;
68
69 // Return true is file is open and $new is unset
70 if($this->filehandle && !$new)
71 return true;
72
73 // Check that new file exitsts
74 if((!(file_exists($file) && is_readable($file))) && !$create)
91be2362 75 return $this->set_error("$file: " . _('No such file or directory'));
5100704d 76
77 // Close old file, if any
78 if($this->filehandle) $this->close();
79
80 // Open file. First try to open for reading and writing,
81 // but fall back to read only.
82 umask($this->umask);
91be2362 83 $fh = @fopen($file, 'a+');
5100704d 84 if($fh) {
85 $this->filehandle = &$fh;
86 $this->filename = $file;
87 $this->writeable = true;
88 } else {
91be2362 89 $fh = @fopen($file, 'r');
5100704d 90 if($fh) {
91 $this->filehandle = &$fh;
92 $this->filename = $file;
93 $this->writeable = false;
94 } else {
91be2362 95 return $this->set_error("$file: " . _('Open failed'));
5100704d 96 }
97 }
98
99 return true;
100 }
101
102 // Close the file and forget the filehandle
103 function close() {
104 @fclose($this->filehandle);
105 $this->filehandle = 0;
91be2362 106 $this->filename = '';
5100704d 107 $this->writable = false;
108 }
d50a8c48 109
110 // Lock the datafile - try 20 times in 5 seconds
111 function lock() {
112 for($i = 0 ; $i < 20 ; $i++) {
113 if(flock($this->filehandle, 2 + 4))
114 return true;
115 else
116 usleep(250000);
117 }
118 return false;
119 }
120
121 // Lock the datafile
122 function unlock() {
123 return flock($this->filehandle, 3);
124 }
125
126 // Overwrite the file with data from $rows
127 // NOTE! Previous locks are broken by this function
128 function overwrite($rows) {
91be2362 129 $newfh = @fopen($this->filename, 'w');
d50a8c48 130 if(!$newfh)
91be2362 131 return $this->set_error("$file: " . _('Open failed'));
d50a8c48 132
133 for($i = 0 ; $i < sizeof($rows) ; $i++) {
134 if(is_array($rows[$i]))
91be2362 135 fwrite($newfh, join('|', $rows[$i]) . '\n');
d50a8c48 136 }
137
138 fclose($newfh);
139 $this->unlock();
140 $this->open(true);
141 return true;
142 }
5100704d 143
144 // ========================== Public ========================
145
146 // Search the file
147 function search($expr) {
148
149 // To be replaced by advanded search expression parsing
150 if(is_array($expr)) return;
151
152 // Make regexp from glob'ed expression
91be2362 153 $expr = ereg_replace('\?', '.', $expr);
154 $expr = ereg_replace('\*', '.*', $expr);
5100704d 155
156 $res = array();
157 if(!$this->open())
158 return false;
159
160 @rewind($this->filehandle);
161
91be2362 162 while ($row = @fgetcsv($this->filehandle, 2048, '|')) {
163 $line = join(' ', $row);
5100704d 164 if(eregi($expr, $line)) {
91be2362 165 array_push($res, array('nickname' => $row[0],
166 'name' => $row[1] . ' ' . $row[2],
167 'firstname' => $row[1],
168 'lastname' => $row[2],
169 'email' => $row[3],
170 'label' => $row[4],
171 'backend' => $this->bnum,
172 'source' => &$this->sname));
5100704d 173 }
174 }
175
176 return $res;
177 }
178
179 // Lookup alias
180 function lookup($alias) {
181 if(empty($alias))
182 return array();
183
184 $alias = strtolower($alias);
185
186 $this->open();
187 @rewind($this->filehandle);
188
91be2362 189 while ($row = @fgetcsv($this->filehandle, 2048, '|')) {
5100704d 190 if(strtolower($row[0]) == $alias) {
91be2362 191 return array('nickname' => $row[0],
192 'name' => $row[1] . ' ' . $row[2],
193 'firstname' => $row[1],
194 'lastname' => $row[2],
195 'email' => $row[3],
196 'label' => $row[4],
197 'backend' => $this->bnum,
198 'source' => &$this->sname);
5100704d 199 }
200 }
201
202 return array();
203 }
204
205 // List all addresses
206 function list_addr() {
207 $res = array();
208 $this->open();
209 @rewind($this->filehandle);
210
91be2362 211 while ($row = @fgetcsv($this->filehandle, 2048, '|')) {
212 array_push($res, array('nickname' => $row[0],
213 'name' => $row[1] . ' ' . $row[2],
214 'firstname' => $row[1],
215 'lastname' => $row[2],
216 'email' => $row[3],
217 'label' => $row[4],
218 'backend' => $this->bnum,
219 'source' => &$this->sname));
5100704d 220 }
221 return $res;
222 }
223
224 // Add address
225 function add($userdata) {
226 if(!$this->writeable)
91be2362 227 return $this->set_error(_('Addressbook is read-only'));
5100704d 228
229 // See if user exist already
91be2362 230 $ret = $this->lookup($userdata['nickname']);
5100704d 231 if(!empty($ret))
91be2362 232 return $this->set_error(sprintf(_('User \'%s\' already exist'),
233 $ret['nickname']));
5100704d 234
235 // Here is the data to write
91be2362 236 $data = $userdata['nickname'] . '|' . $userdata['firstname'] . '|' .
237 $userdata['lastname'] . '|' . $userdata['email'] . '|' .
238 $userdata['label'];
5100704d 239 // Strip linefeeds
91be2362 240 $data = ereg_replace('[\r\n]', ' ', $data);
5100704d 241 // Add linefeed at end
91be2362 242 $data = $data . '\n';
5100704d 243
244 // Reopen file, just to be sure
245 $this->open(true);
246 if(!$this->writeable)
91be2362 247 return $this->set_error(_('Addressbook is read-only'));
5100704d 248
d50a8c48 249 // Lock the file
250 if(!$this->lock())
91be2362 251 return $this->set_error(_('Could not lock datafile'));
d50a8c48 252
253 // Write
5100704d 254 $r = fwrite($this->filehandle, $data);
5100704d 255
d50a8c48 256 // Unlock file
257 $this->unlock();
258
259 // Test write result and exit if OK
260 if($r > 0) return true;
261
262 // Fail
91be2362 263 $this->set_error(_('Write to addressbook failed'));
5100704d 264 return false;
265 }
266
d50a8c48 267 // Delete address
268 function remove($alias) {
269 if(!$this->writeable)
91be2362 270 return $this->set_error(_('Addressbook is read-only'));
d50a8c48 271
272 // Lock the file to make sure we're the only process working
273 // on it.
274 if(!$this->lock())
91be2362 275 return $this->set_error(_('Could not lock datafile'));
d50a8c48 276
277 // Read file into memory, ignoring nicknames to delete
278 $this->open();
279 @rewind($this->filehandle);
280 $i = 0;
281 $rows = array();
91be2362 282 while($row = @fgetcsv($this->filehandle, 2048, '|')) {
d50a8c48 283 if(!in_array($row[0], $alias))
284 $rows[$i++] = $row;
285 }
286
287 // Write data back
288 if(!$this->overwrite(&$rows)) {
289 $this->unlock();
290 return false;
291 }
292
293 $this->unlock();
294 return true;
295 }
296
297 // Modify address
298 function modify($alias, $userdata) {
299 if(!$this->writeable)
91be2362 300 return $this->set_error(_('Addressbook is read-only'));
d50a8c48 301
302 // See if user exist
303 $ret = $this->lookup($alias);
304 if(empty($ret))
91be2362 305 return $this->set_error(sprintf(_('User \'%s\' does not exist'),
d50a8c48 306 $alias));
307
308 // Lock the file to make sure we're the only process working
309 // on it.
310 if(!$this->lock())
91be2362 311 return $this->set_error(_('Could not lock datafile'));
d50a8c48 312
313 // Read file into memory, modifying the data for the
314 // user identifyed by $alias
315 $this->open();
316 @rewind($this->filehandle);
317 $i = 0;
318 $rows = array();
91be2362 319 while($row = @fgetcsv($this->filehandle, 2048, '|')) {
d50a8c48 320 if(strtolower($row[0]) != strtolower($alias)) {
321 $rows[$i++] = $row;
322 } else {
91be2362 323 $rows[$i++] = array(0 => $userdata['nickname'],
324 1 => $userdata['firstname'],
325 2 => $userdata['lastname'],
326 3 => $userdata['email'],
327 4 => $userdata['label']);
d50a8c48 328 }
329 }
330
331 // Write data back
332 if(!$this->overwrite(&$rows)) {
333 $this->unlock();
334 return false;
335 }
336
337 $this->unlock();
338 return true;
339 }
340
341 } // End of class abook_local_file
5100704d 342?>