<?php
+
/**
* abook_local_file.php
*
- * Copyright (c) 1999-2005 The SquirrelMail Project Team
- * Licensed under the GNU GPL. For full terms see the file COPYING.
- *
+ * @copyright 1999-2010 The SquirrelMail Project Team
+ * @license http://opensource.org/licenses/gpl-license.php GNU Public License
* @version $Id$
* @package squirrelmail
* @subpackage addressbook
* @var string
*/
var $umask;
+ /**
+ * Sets max entry size (number of bytes used for all address book fields
+ * (including escapes) + 4 delimiters + 1 linefeed)
+ * @var integer
+ * @since 1.5.2
+ */
+ var $line_length = 2048;
/* ========================== Private ======================= */
* @return bool
*/
function abook_local_file($param) {
- $this->sname = _("Personal address book");
+ $this->sname = _("Personal Address Book");
$this->umask = Umask();
if(is_array($param)) {
if(isset($param['listing'])) {
$this->listing = $param['listing'];
}
+ if(isset($param['line_length']) && ! empty($param['line_length'])) {
+ $this->line_length = (int) $param['line_length'];
+ }
$this->open(true);
} else {
$this->error = '';
$file = $this->filename;
$create = $this->create;
- $fopenmode = (($this->writeable && is_writable($file)) ? 'a+' : 'r');
+ $fopenmode = (($this->writeable && sq_is_writable($file)) ? 'a+' : 'r');
/* Return true is file is open and $new is unset */
if($this->filehandle && !$new) {
return $this->set_error($this->filename . ':' . _("Unable to update"));
}
@unlink($this->filename . '.tmp');
+ @chmod($this->filename, 0600);
$this->unlock();
$this->open(true);
return true;
}
@rewind($this->filehandle);
- while ($row = @fgetcsv($this->filehandle, 2048, '|')) {
- $line = join(' ', $row);
- if(eregi($expr, $line)) {
- array_push($res, array('nickname' => $row[0],
- 'name' => $row[1] . ' ' . $row[2],
- 'firstname' => $row[1],
- 'lastname' => $row[2],
- 'email' => $row[3],
- 'label' => $row[4],
- 'backend' => $this->bnum,
- 'source' => &$this->sname));
+ while ($row = @fgetcsv($this->filehandle, $this->line_length, '|')) {
+ if (count($row)<5) {
+ /**
+ * address book is corrupted.
+ */
+ global $oTemplate;
+ error_box(_("Address book is corrupted. Required fields are missing."));
+ $oTemplate->display('footer.tpl');
+ die();
+ } else {
+ $line = join(' ', $row);
+ /**
+ * TODO: regexp search is supported only in local_file backend.
+ * Do we check format of regexp or ignore errors?
+ */
+ // errors on preg_match call are suppressed in order to prevent display of regexp compilation errors
+ if(@preg_match('/' . $expr . '/i', $line)) {
+ array_push($res, array('nickname' => $row[0],
+ 'name' => $this->fullname($row[1], $row[2]),
+ 'firstname' => $row[1],
+ 'lastname' => $row[2],
+ 'email' => $row[3],
+ 'label' => $row[4],
+ 'backend' => $this->bnum,
+ 'source' => &$this->sname));
+ }
}
}
}
/**
- * Lookup alias
- * @param string $alias alias
- * @return array search results
+ * Lookup an address by the indicated field.
+ *
+ * @param string $value The value to look up
+ * @param integer $field The field to look in, should be one
+ * of the SM_ABOOK_FIELD_* constants
+ * defined in include/constants.php
+ * (OPTIONAL; defaults to nickname field)
+ * NOTE: uniqueness is only guaranteed
+ * when the nickname field is used here;
+ * otherwise, the first matching address
+ * is returned.
+ *
+ * @return array Array with lookup results when the value
+ * was found, an empty array if the value was
+ * not found.
+ *
*/
- function lookup($alias) {
- if(empty($alias)) {
+ function lookup($value, $field=SM_ABOOK_FIELD_NICKNAME) {
+ if(empty($value)) {
return array();
}
- $alias = strtolower($alias);
+ $value = strtolower($value);
$this->open();
@rewind($this->filehandle);
- while ($row = @fgetcsv($this->filehandle, 2048, '|')) {
- if(strtolower($row[0]) == $alias) {
- return array('nickname' => $row[0],
- 'name' => $row[1] . ' ' . $row[2],
- 'firstname' => $row[1],
- 'lastname' => $row[2],
- 'email' => $row[3],
- 'label' => $row[4],
- 'backend' => $this->bnum,
- 'source' => &$this->sname);
+ while ($row = @fgetcsv($this->filehandle, $this->line_length, '|')) {
+ if (count($row)<5) {
+ /**
+ * address book is corrupted.
+ */
+ global $oTemplate;
+ error_box(_("Address book is corrupted. Required fields are missing."));
+ $oTemplate->display('footer.tpl');
+ die();
+ } else {
+ if(strtolower($row[$field]) == $value) {
+ return array('nickname' => $row[0],
+ 'name' => $this->fullname($row[1], $row[2]),
+ 'firstname' => $row[1],
+ 'lastname' => $row[2],
+ 'email' => $row[3],
+ 'label' => $row[4],
+ 'backend' => $this->bnum,
+ 'source' => &$this->sname);
+ }
}
}
$this->open();
@rewind($this->filehandle);
- while ($row = @fgetcsv($this->filehandle, 2048, '|')) {
- array_push($res, array('nickname' => $row[0],
- 'name' => $row[1] . ' ' . $row[2],
- 'firstname' => $row[1],
- 'lastname' => $row[2],
- 'email' => $row[3],
- 'label' => $row[4],
- 'backend' => $this->bnum,
- 'source' => &$this->sname));
+ while ($row = @fgetcsv($this->filehandle, $this->line_length, '|')) {
+ if (count($row)<5) {
+ /**
+ * address book is corrupted. Don't be nice to people that
+ * violate address book formating.
+ */
+ global $oTemplate;
+ error_box(_("Address book is corrupted. Required fields are missing."));
+ $oTemplate->display('footer.tpl');
+ die();
+ } else {
+ array_push($res, array('nickname' => $row[0],
+ 'name' => $this->fullname($row[1], $row[2]),
+ 'firstname' => $row[1],
+ 'lastname' => $row[2],
+ 'email' => $row[3],
+ 'label' => $row[4],
+ 'backend' => $this->bnum,
+ 'source' => &$this->sname));
+ }
}
return $res;
}
*/
function add($userdata) {
if(!$this->writeable) {
- return $this->set_error(_("Addressbook is read-only"));
+ return $this->set_error(_("Address book is read-only"));
}
/* See if user exists already */
$ret = $this->lookup($userdata['nickname']);
if(!empty($ret)) {
- return $this->set_error(sprintf(_("User %s already exists"),
- '"' . $ret['nickname'] . '"'));
+ // i18n: don't use html formating in translation
+ return $this->set_error(sprintf(_("User \"%s\" already exists"),$ret['nickname']));
}
/* Here is the data to write */
$data = $this->quotevalue($userdata['nickname']) . '|' .
$this->quotevalue($userdata['firstname']) . '|' .
- $this->quotevalue($userdata['lastname']) . '|' .
+ $this->quotevalue((!empty($userdata['lastname'])?$userdata['lastname']:'')) . '|' .
$this->quotevalue($userdata['email']) . '|' .
- $this->quotevalue($userdata['label']);
+ $this->quotevalue((!empty($userdata['label'])?$userdata['label']:''));
/* Strip linefeeds */
- $data = ereg_replace("[\r\n]", ' ', $data);
+ $nl_str = array("\r","\n");
+ $data = str_replace($nl_str, ' ', $data);
+
+ /**
+ * Make sure that entry fits into allocated record space.
+ * One byte is reserved for linefeed
+ */
+ if (strlen($data) >= $this->line_length) {
+ return $this->set_error(_("Address book entry is too big"));
+ }
+
/* 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"));
+ return $this->set_error(_("Address book is read-only"));
}
/* Lock the file */
/* Test write result */
if($r === FALSE) {
/* Fail */
- $this->set_error(_("Write to addressbook failed"));
+ $this->set_error(_("Write to address book failed"));
return FALSE;
}
*/
function remove($alias) {
if(!$this->writeable) {
- return $this->set_error(_("Addressbook is read-only"));
+ return $this->set_error(_("Address book is read-only"));
}
/* Lock the file to make sure we're the only process working
@rewind($this->filehandle);
$i = 0;
$rows = array();
- while($row = @fgetcsv($this->filehandle, 2048, '|')) {
+ while($row = @fgetcsv($this->filehandle, $this->line_length, '|')) {
if(!in_array($row[0], $alias)) {
$rows[$i++] = $row;
}
*/
function modify($alias, $userdata) {
if(!$this->writeable) {
- return $this->set_error(_("Addressbook is read-only"));
+ return $this->set_error(_("Address book 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 . '"'));
+ // i18n: don't use html formating in translation
+ return $this->set_error(sprintf(_("User \"%s\" does not exist"),$alias));
}
-
+
+ /* If the alias changed, see if the new alias exists */
+ if (strtolower($alias) != strtolower($userdata['nickname'])) {
+ $ret = $this->lookup($userdata['nickname']);
+ if (!empty($ret)) {
+ return $this->set_error(sprintf(_("User \"%s\" already exists"), $userdata['nickname']));
+ }
+ }
+
/* 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"));
}
+ /* calculate userdata size */
+ $data = $this->quotevalue($userdata['nickname']) . '|'
+ . $this->quotevalue($userdata['firstname']) . '|'
+ . $this->quotevalue((!empty($userdata['lastname'])?$userdata['lastname']:'')) . '|'
+ . $this->quotevalue($userdata['email']) . '|'
+ . $this->quotevalue((!empty($userdata['label'])?$userdata['label']:''));
+ /* make sure that it fits into allocated space */
+ if (strlen($data) >= $this->line_length) {
+ return $this->set_error(_("Address book entry is too big"));
+ }
+
/* Read file into memory, modifying the data for the
* user identified by $alias */
$this->open(true);
@rewind($this->filehandle);
$i = 0;
$rows = array();
- while($row = @fgetcsv($this->filehandle, 2048, '|')) {
+ while($row = @fgetcsv($this->filehandle, $this->line_length, '|')) {
if(strtolower($row[0]) != strtolower($alias)) {
$rows[$i++] = $row;
} else {
$rows[$i++] = array(0 => $userdata['nickname'],
1 => $userdata['firstname'],
- 2 => $userdata['lastname'],
+ 2 => (!empty($userdata['lastname'])?$userdata['lastname']:''),
3 => $userdata['email'],
- 4 => $userdata['label']);
+ 4 => (!empty($userdata['label'])?$userdata['label']:''));
}
}
function quotevalue($value) {
/* Quote the field if it contains | or ". Double quotes need to
* be replaced with "" */
- if(ereg("[|\"]", $value)) {
+ if(stristr($value, '"') || stristr($value, '|')) {
$value = '"' . str_replace('"', '""', $value) . '"';
}
return $value;
}
-
-} /* End of class abook_local_file */
-?>
\ No newline at end of file
+}