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