4 ** abook_local_file.php
6 ** Backend for addressbook as a pipe separated file
8 ** An array with the following elements must be passed to
9 ** the class constructor (elements marked ? are optional):
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.
15 ** NOTE. This class should not be used directly. Use the
16 ** "AddressBook" class instead.
19 class abook_local_file
extends addressbook_backend
{
21 var $bname = "local_file";
28 // ========================== Private =======================
31 function abook_local_file($param) {
32 $this->sname
= _("Personal address book");
33 $this->umask
= Umask();
35 if(is_array($param)) {
36 if(empty($param["filename"]))
37 return $this->set_error("Invalid parameters");
38 if(!is_string($param["filename"]))
39 return $this->set_error($param["filename"] . ": ".
40 _("Not a file name"));
42 $this->filename
= $param["filename"];
46 if(isset($param["umask"]))
47 $this->umask
= $param["umask"];
49 if(!empty($param["name"]))
50 $this->sname
= $param["name"];
54 $this->set_error("Invalid argument to constructor");
58 // Open the addressbook file and store the file pointer.
59 // Use $file as the file to open, or the class' own
60 // filename property. If $param is empty and file is
62 function open($new = false) {
64 $file = $this->filename
;
65 $create = $this->create
;
67 // Return true is file is open and $new is unset
68 if($this->filehandle
&& !$new)
71 // Check that new file exitsts
72 if((!(file_exists($file) && is_readable($file))) && !$create)
73 return $this->set_error("$file: " .
74 _("No such file or directory"));
76 // Close old file, if any
77 if($this->filehandle
) $this->close();
79 // Open file. First try to open for reading and writing,
80 // but fall back to read only.
82 $fh = @fopen
($file, "a+");
84 $this->filehandle
= &$fh;
85 $this->filename
= $file;
86 $this->writeable
= true;
88 $fh = @fopen
($file, "r");
90 $this->filehandle
= &$fh;
91 $this->filename
= $file;
92 $this->writeable
= false;
94 return $this->set_error("$file: "._("Open failed"));
101 // Close the file and forget the filehandle
103 @fclose
($this->filehandle
);
104 $this->filehandle
= 0;
105 $this->filename
= "";
106 $this->writable
= false;
109 // Lock the datafile - try 20 times in 5 seconds
111 for($i = 0 ; $i < 20 ; $i++
) {
112 if(flock($this->filehandle
, 2 +
4))
122 return flock($this->filehandle
, 3);
125 // Overwrite the file with data from $rows
126 // NOTE! Previous locks are broken by this function
127 function overwrite($rows) {
128 $newfh = @fopen
($this->filename
, "w");
130 return $this->set_error("$file: "._("Open failed"));
132 for($i = 0 ; $i < sizeof($rows) ; $i++
) {
133 if(is_array($rows[$i]))
134 fwrite($newfh, join("|", $rows[$i])."\n");
143 // ========================== Public ========================
146 function search($expr) {
148 // To be replaced by advanded search expression parsing
149 if(is_array($expr)) return;
151 // Make regexp from glob'ed expression
152 $expr = ereg_replace("\?", ".", $expr);
153 $expr = ereg_replace("\*", ".*", $expr);
159 @rewind
($this->filehandle
);
161 while ($row = @fgetcsv
($this->filehandle
, 2048, "|")) {
162 $line = join(" ", $row);
163 if(eregi($expr, $line)) {
164 array_push($res, array("nickname" => $row[0],
165 "name" => $row[1] . " " . $row[2],
166 "firstname" => $row[1],
167 "lastname" => $row[2],
170 "backend" => $this->bnum
,
171 "source" => &$this->sname
));
179 function lookup($alias) {
183 $alias = strtolower($alias);
186 @rewind
($this->filehandle
);
188 while ($row = @fgetcsv
($this->filehandle
, 2048, "|")) {
189 if(strtolower($row[0]) == $alias) {
190 return array("nickname" => $row[0],
191 "name" => $row[1] . " " . $row[2],
192 "firstname" => $row[1],
193 "lastname" => $row[2],
196 "backend" => $this->bnum
,
197 "source" => &$this->sname
);
204 // List all addresses
205 function list_addr() {
208 @rewind
($this->filehandle
);
210 while ($row = @fgetcsv
($this->filehandle
, 2048, "|")) {
211 array_push($res, 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
));
224 function add($userdata) {
225 if(!$this->writeable
)
226 return $this->set_error(_("Addressbook is read-only"));
228 // See if user exist already
229 $ret = $this->lookup($userdata["nickname"]);
231 return $this->set_error(sprintf(_("User '%s' already exist"),
234 // Here is the data to write
235 $data = sprintf("%s|%s|%s|%s|%s", $userdata["nickname"],
236 $userdata["firstname"], $userdata["lastname"],
237 $userdata["email"], $userdata["label"]);
239 $data = ereg_replace("[\r\n]", " ", $data);
240 // Add linefeed at end
243 // Reopen file, just to be sure
245 if(!$this->writeable
)
246 return $this->set_error(_("Addressbook is read-only"));
250 return $this->set_error(_("Could not lock datafile"));
253 $r = fwrite($this->filehandle
, $data);
258 // Test write result and exit if OK
259 if($r > 0) return true;
262 $this->set_error(_("Write to addressbook failed"));
267 function remove($alias) {
268 if(!$this->writeable
)
269 return $this->set_error(_("Addressbook is read-only"));
271 // Lock the file to make sure we're the only process working
274 return $this->set_error(_("Could not lock datafile"));
276 // Read file into memory, ignoring nicknames to delete
278 @rewind
($this->filehandle
);
281 while($row = @fgetcsv
($this->filehandle
, 2048, "|")) {
282 if(!in_array($row[0], $alias))
287 if(!$this->overwrite(&$rows)) {
297 function modify($alias, $userdata) {
298 if(!$this->writeable
)
299 return $this->set_error(_("Addressbook is read-only"));
302 $ret = $this->lookup($alias);
304 return $this->set_error(sprintf(_("User '%s' does not exist"),
307 // Lock the file to make sure we're the only process working
310 return $this->set_error(_("Could not lock datafile"));
312 // Read file into memory, modifying the data for the
313 // user identifyed by $alias
315 @rewind
($this->filehandle
);
318 while($row = @fgetcsv
($this->filehandle
, 2048, "|")) {
319 if(strtolower($row[0]) != strtolower($alias)) {
322 $rows[$i++
] = array(0 => $userdata["nickname"],
323 1 => $userdata["firstname"],
324 2 => $userdata["lastname"],
325 3 => $userdata["email"],
326 4 => $userdata["label"]);
331 if(!$this->overwrite(&$rows)) {
340 } // End of class abook_local_file