6 * Copyright (c) 1999-2002 The SquirrelMail Project Team
7 * Licensed under the GNU GPL. For full terms see the file COPYING.
9 * Backend for addressbook as a pipe separated file
11 * An array with the following elements must be passed to
12 * the class constructor (elements marked ? are optional):
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.
18 * NOTE. This class should not be used directly. Use the
19 * "AddressBook" class instead.
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 /*****************************************************************/
40 class abook_local_file
extends addressbook_backend
{
42 var $bname = 'local_file';
49 // ========================== Private =======================
52 function abook_local_file($param) {
53 $this->sname
= _("Personal address book");
54 $this->umask
= Umask();
56 if(is_array($param)) {
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'] . ': '.
61 _("Not a file name"));
63 $this->filename
= $param['filename'];
67 if(isset($param['umask']))
68 $this->umask
= $param['umask'];
70 if(!empty($param['name']))
71 $this->sname
= $param['name'];
75 $this->set_error('Invalid argument to constructor');
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
83 function open($new = false) {
85 $file = $this->filename
;
86 $create = $this->create
;
88 // Return true is file is open and $new is unset
89 if($this->filehandle
&& !$new)
92 // Check that new file exitsts
93 if((!(file_exists($file) && is_readable($file))) && !$create)
94 return $this->set_error("$file: " . _("No such file or directory"));
96 // Close old file, if any
97 if($this->filehandle
) $this->close();
99 // Open file. First try to open for reading and writing,
100 // but fall back to read only.
102 $fh = @fopen
($file, 'a+');
104 $this->filehandle
= &$fh;
105 $this->filename
= $file;
106 $this->writeable
= true;
108 $fh = @fopen
($file, 'r');
110 $this->filehandle
= &$fh;
111 $this->filename
= $file;
112 $this->writeable
= false;
114 return $this->set_error("$file: " . _("Open failed"));
121 // Close the file and forget the filehandle
123 @fclose
($this->filehandle
);
124 $this->filehandle
= 0;
125 $this->filename
= '';
126 $this->writable
= false;
129 // Lock the datafile - try 20 times in 5 seconds
131 for($i = 0 ; $i < 20 ; $i++
) {
132 if(flock($this->filehandle
, 2 +
4))
142 return flock($this->filehandle
, 3);
145 // Overwrite the file with data from $rows
146 // NOTE! Previous locks are broken by this function
147 function overwrite(&$rows) {
148 $newfh = @fopen
($this->filename
, 'w');
150 return $this->set_error("$file: " . _("Open failed"));
152 for($i = 0 ; $i < sizeof($rows) ; $i++
) {
153 if(is_array($rows[$i]))
154 fwrite($newfh, join('|', $rows[$i]) . "\n");
163 // ========================== Public ========================
166 function search($expr) {
168 // To be replaced by advanded search expression parsing
169 if(is_array($expr)) return;
171 // Make regexp from glob'ed expression
172 // May want to quote other special characters like (, ), -, [, ], etc.
173 $expr = str_replace('?', '.', $expr);
174 $expr = str_replace('*', '.*', $expr);
180 @rewind
($this->filehandle
);
182 while ($row = @fgetcsv
($this->filehandle
, 2048, '|')) {
183 $line = join(' ', $row);
184 if(eregi($expr, $line)) {
185 array_push($res, array('nickname' => $row[0],
186 'name' => $row[1] . ' ' . $row[2],
187 'firstname' => $row[1],
188 'lastname' => $row[2],
191 'backend' => $this->bnum
,
192 'source' => &$this->sname
));
200 function lookup($alias) {
204 $alias = strtolower($alias);
207 @rewind
($this->filehandle
);
209 while ($row = @fgetcsv
($this->filehandle
, 2048, '|')) {
210 if(strtolower($row[0]) == $alias) {
211 return array('nickname' => $row[0],
212 'name' => $row[1] . ' ' . $row[2],
213 'firstname' => $row[1],
214 'lastname' => $row[2],
217 'backend' => $this->bnum
,
218 'source' => &$this->sname
);
225 // List all addresses
226 function list_addr() {
229 @rewind
($this->filehandle
);
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],
238 'backend' => $this->bnum
,
239 'source' => &$this->sname
));
245 function add($userdata) {
246 if(!$this->writeable
)
247 return $this->set_error(_("Addressbook is read-only"));
249 // See if user exist already
250 $ret = $this->lookup($userdata['nickname']);
252 return $this->set_error(sprintf(_("User '%s' already exist"),
255 // Here is the data to write
256 $data = $userdata['nickname'] . '|' . $userdata['firstname'] . '|' .
257 $userdata['lastname'] . '|' . $userdata['email'] . '|' .
260 $data = ereg_replace("[\r\n]", ' ', $data);
261 // Add linefeed at end
262 $data = $data . "\n";
264 // Reopen file, just to be sure
266 if(!$this->writeable
)
267 return $this->set_error(_("Addressbook is read-only"));
271 return $this->set_error(_("Could not lock datafile"));
274 $r = fwrite($this->filehandle
, $data);
279 // Test write result and exit if OK
280 if($r > 0) return true;
283 $this->set_error(_("Write to addressbook failed"));
288 function remove($alias) {
289 if(!$this->writeable
)
290 return $this->set_error(_("Addressbook is read-only"));
292 // Lock the file to make sure we're the only process working
295 return $this->set_error(_("Could not lock datafile"));
297 // Read file into memory, ignoring nicknames to delete
298 @rewind
($this->filehandle
);
301 while($row = @fgetcsv
($this->filehandle
, 2048, '|')) {
302 if(!in_array($row[0], $alias))
307 if(!$this->overwrite($rows)) {
317 function modify($alias, $userdata) {
318 if(!$this->writeable
)
319 return $this->set_error(_("Addressbook is read-only"));
322 $ret = $this->lookup($alias);
324 return $this->set_error(sprintf(_("User '%s' does not exist"),
327 // Lock the file to make sure we're the only process working
330 return $this->set_error(_("Could not lock datafile"));
332 // Read file into memory, modifying the data for the
333 // user identifyed by $alias
335 @rewind
($this->filehandle
);
338 while($row = @fgetcsv
($this->filehandle
, 2048, '|')) {
339 if(strtolower($row[0]) != strtolower($alias)) {
342 $rows[$i++
] = array(0 => $userdata['nickname'],
343 1 => $userdata['firstname'],
344 2 => $userdata['lastname'],
345 3 => $userdata['email'],
346 4 => $userdata['label']);
351 if(!$this->overwrite($rows)) {
360 } // End of class abook_local_file