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