/**
* abook_local_file.php
*
- * Copyright (c) 1999-2002 The SquirrelMail Project Team
+ * Copyright (c) 1999-2004 The SquirrelMail Project Team
* Licensed under the GNU GPL. For full terms see the file COPYING.
*
* Backend for addressbook as a pipe separated file
* NOTE. This class should not be used directly. Use the
* "AddressBook" class instead.
*
- * $Id$
+ * @version $Id$
+ * @package squirrelmail
+ * @subpackage addressbook
*/
+/**
+ * Store the addressbook in a local file
+ * @package squirrelmail
+ */
class abook_local_file extends addressbook_backend {
var $btype = 'local';
var $bname = 'local_file';
if(!empty($param['name'])) {
$this->sname = $param['name'];
}
-
+
$this->open(true);
} else {
$this->set_error('Invalid argument to constructor');
}
/* Open the addressbook file and store the file pointer.
- * Use $file as the file to open, or the class' own
- * filename property. If $param is empty and file is
+ * Use $file as the file to open, or the class' own
+ * filename property. If $param is empty and file is
* open, do nothing. */
function open($new = false) {
$this->error = '';
$file = $this->filename;
$create = $this->create;
-
+
/* Return true is file is open and $new is unset */
if($this->filehandle && !$new) {
return true;
}
-
+
/* Check that new file exitsts */
if((!(file_exists($file) && is_readable($file))) && !$create) {
return $this->set_error("$file: " . _("No such file or directory"));
}
-
+
/* Close old file, if any */
if($this->filehandle) { $this->close(); }
-
+
/* Open file. First try to open for reading and writing,
* but fall back to read only. */
umask($this->umask);
/* Lock the datafile - try 20 times in 5 seconds */
function lock() {
for($i = 0 ; $i < 20 ; $i++) {
- if(flock($this->filehandle, 2 + 4))
+ if(flock($this->filehandle, 2 + 4))
return true;
else
usleep(250000);
* NOTE! Previous locks are broken by this function */
function overwrite(&$rows) {
$this->unlock();
- $newfh = @fopen($this->filename, 'w');
+ $newfh = @fopen($this->filename.'.tmp', 'w');
+
if(!$newfh) {
- return $this->set_error("$file: " . _("Open failed"));
+ return $this->set_error($this->filename. '.tmp:' . _("Open failed"));
}
-
- for($i = 0 ; $i < sizeof($rows) ; $i++) {
+
+ for($i = 0, $cnt=sizeof($rows) ; $i < $cnt ; $i++) {
if(is_array($rows[$i])) {
- fwrite($newfh, join('|', $rows[$i]) . "\n");
+ for($j = 0, $cnt_part=count($rows[$i]) ; $j < $cnt_part ; $j++) {
+ $rows[$i][$j] = $this->quotevalue($rows[$i][$j]);
+ }
+ $tmpwrite = sq_fwrite($newfh, join('|', $rows[$i]) . "\n");
+ if ($tmpwrite === FALSE) {
+ return $this->set_error($this->filename . '.tmp:' . _("Write failed"));
+ }
}
- }
+ }
fclose($newfh);
+ if (!@copy($this->filename . '.tmp' , $this->filename)) {
+ return $this->set_error($this->filename . ':' . _("Unable to update"));
+ }
+ @unlink($this->filename . '.tmp');
$this->unlock();
$this->open(true);
return true;
}
-
+
/* ========================== Public ======================== */
-
+
/* Search the file */
function search($expr) {
/* To be replaced by advanded search expression parsing */
if(is_array($expr)) { return; }
-
+
/* Make regexp from glob'ed expression
* May want to quote other special characters like (, ), -, [, ], etc. */
$expr = str_replace('?', '.', $expr);
$expr = str_replace('*', '.*', $expr);
-
+
$res = array();
if(!$this->open()) {
return false;
}
@rewind($this->filehandle);
-
+
while ($row = @fgetcsv($this->filehandle, 2048, '|')) {
$line = join(' ', $row);
if(eregi($expr, $line)) {
'source' => &$this->sname));
}
}
-
+
return $res;
}
-
+
/* Lookup alias */
function lookup($alias) {
if(empty($alias)) {
}
$alias = strtolower($alias);
-
+
$this->open();
@rewind($this->filehandle);
-
+
while ($row = @fgetcsv($this->filehandle, 2048, '|')) {
if(strtolower($row[0]) == $alias) {
return array('nickname' => $row[0],
'source' => &$this->sname);
}
}
-
+
return array();
}
$res = array();
$this->open();
@rewind($this->filehandle);
-
+
while ($row = @fgetcsv($this->filehandle, 2048, '|')) {
array_push($res, array('nickname' => $row[0],
'name' => $row[1] . ' ' . $row[2],
return $this->set_error(sprintf(_("User '%s' already exist"),
$ret['nickname']));
}
-
+
/* Here is the data to write */
- $data = $userdata['nickname'] . '|' . $userdata['firstname'] . '|' .
- $userdata['lastname'] . '|' . $userdata['email'] . '|' .
- $userdata['label'];
+ $data = $this->quotevalue($userdata['nickname']) . '|' .
+ $this->quotevalue($userdata['firstname']) . '|' .
+ $this->quotevalue($userdata['lastname']) . '|' .
+ $this->quotevalue($userdata['email']) . '|' .
+ $this->quotevalue($userdata['label']);
+
/* Strip linefeeds */
$data = ereg_replace("[\r\n]", ' ', $data);
/* Add linefeed at end */
$data = $data . "\n";
-
+
/* Reopen file, just to be sure */
$this->open(true);
if(!$this->writeable) {
return $this->set_error(_("Addressbook is read-only"));
}
-
+
/* Lock the file */
if(!$this->lock()) {
return $this->set_error(_("Could not lock datafile"));
}
-
+
/* Write */
- $r = fwrite($this->filehandle, $data);
-
+ $r = sq_fwrite($this->filehandle, $data);
+
/* Unlock file */
$this->unlock();
-
- /* Test write result and exit if OK */
- if($r > 0) return true;
-
- /* Fail */
- $this->set_error(_("Write to addressbook failed"));
- return false;
+
+ /* Test write result */
+ if($r === FALSE) {
+ /* Fail */
+ $this->set_error(_("Write to addressbook failed"));
+ return FALSE;
+ }
+
+ return TRUE;
}
/* Delete address */
if(!$this->writeable) {
return $this->set_error(_("Addressbook is read-only"));
}
-
+
/* Lock the file to make sure we're the only process working
* on it. */
if(!$this->lock()) {
return $this->set_error(_("Could not lock datafile"));
}
-
+
/* Read file into memory, ignoring nicknames to delete */
@rewind($this->filehandle);
$i = 0;
$rows[$i++] = $row;
}
}
-
+
/* Write data back */
if(!$this->overwrite($rows)) {
$this->unlock();
return false;
}
-
+
$this->unlock();
return true;
}
if(!$this->writeable) {
return $this->set_error(_("Addressbook is read-only"));
}
-
+
/* See if user exists */
$ret = $this->lookup($alias);
if(empty($ret)) {
return $this->set_error(sprintf(_("User '%s' does not exist"),
$alias));
}
-
+
/* Lock the file to make sure we're the only process working
* on it. */
if(!$this->lock()) {
return $this->set_error(_("Could not lock datafile"));
}
-
- /* Read file into memory, modifying the data for the
+
+ /* Read file into memory, modifying the data for the
* user identified by $alias */
$this->open(true);
@rewind($this->filehandle);
$rows[$i++] = array(0 => $userdata['nickname'],
1 => $userdata['firstname'],
2 => $userdata['lastname'],
- 3 => $userdata['email'],
+ 3 => $userdata['email'],
4 => $userdata['label']);
}
}
-
+
/* Write data back */
if(!$this->overwrite($rows)) {
$this->unlock();
return false;
}
-
+
$this->unlock();
return true;
}
-
+
+ /* Function for quoting values before saving */
+ function quotevalue($value) {
+ /* Quote the field if it contains | or ". Double quotes need to
+ * be replaced with "" */
+ if(ereg("[|\"]", $value)) {
+ $value = '"' . str_replace('"', '""', $value) . '"';
+ }
+ return $value;
+ }
+
} /* End of class abook_local_file */
?>
\ No newline at end of file