squirrelmail-webmail  1.4.22
About: SquirrelMail is a standards-based webmail package with strong MIME support, address books, and folder manipulation (written in PHP4).
  Fossies Dox: squirrelmail-webmail-1.4.22.tar.gz  ("inofficial" and yet experimental doxygen-generated source code documentation)  

abook_local_file.php
Go to the documentation of this file.
1 <?php
2 
41  var $btype = 'local';
46  var $bname = 'local_file';
47 
52  var $filename = '';
57  var $filehandle = 0;
62  var $create = false;
67  var $detect_writeable = true;
74  var $writeable = false;
80  var $listing = true;
85  var $umask;
92  var $line_length = 2048;
93 
94  /* ========================== Private ======================= */
95 
101  function abook_local_file($param) {
102  $this->sname = _("Personal address book");
103  $this->umask = Umask();
104 
105  if(is_array($param)) {
106  if(empty($param['filename'])) {
107  return $this->set_error('Invalid parameters');
108  }
109  if(!is_string($param['filename'])) {
110  return $this->set_error($param['filename'] . ': '.
111  _("Not a file name"));
112  }
113 
114  $this->filename = $param['filename'];
115 
116  if(isset($param['create'])) {
117  $this->create = $param['create'];
118  }
119  if(isset($param['umask'])) {
120  $this->umask = $param['umask'];
121  }
122  if(isset($param['name'])) {
123  $this->sname = $param['name'];
124  }
125  if(isset($param['detect_writeable'])) {
126  $this->detect_writeable = $param['detect_writeable'];
127  }
128  if(!empty($param['writeable'])) {
129  $this->writeable = $param['writeable'];
130  }
131  if(isset($param['listing'])) {
132  $this->listing = $param['listing'];
133  }
134  if(isset($param['line_length']) && ! empty($param['line_length'])) {
135  $this->line_length = (int) $param['line_length'];
136  }
137 
138  $this->open(true);
139  } else {
140  $this->set_error('Invalid argument to constructor');
141  }
142  }
143 
152  function open($new = false) {
153  $this->error = '';
154  $file = $this->filename;
156  $fopenmode = (($this->writeable && is_writable($file)) ? 'a+' : 'r');
157 
158  /* Return true is file is open and $new is unset */
159  if($this->filehandle && !$new) {
160  return true;
161  }
162 
163  /* Check that new file exitsts */
164  if((!(file_exists($file) && is_readable($file))) && !$create) {
165  return $this->set_error("$file: " . _("No such file or directory"));
166  }
167 
168  /* Close old file, if any */
169  if($this->filehandle) { $this->close(); }
170 
171  umask($this->umask);
172  if (! $this->detect_writeable) {
173  $fh = @fopen($file,$fopenmode);
174  if ($fh) {
175  $this->filehandle = &$fh;
176  $this->filename = $file;
177  } else {
178  return $this->set_error("$file: " . _("Open failed"));
179  }
180  } else {
181  /* Open file. First try to open for reading and writing,
182  * but fall back to read only. */
183  $fh = @fopen($file, 'a+');
184  if($fh) {
185  $this->filehandle = &$fh;
186  $this->filename = $file;
187  $this->writeable = true;
188  } else {
189  $fh = @fopen($file, 'r');
190  if($fh) {
191  $this->filehandle = &$fh;
192  $this->filename = $file;
193  $this->writeable = false;
194  } else {
195  return $this->set_error("$file: " . _("Open failed"));
196  }
197  }
198  }
199  return true;
200  }
201 
203  function close() {
204  @fclose($this->filehandle);
205  $this->filehandle = 0;
206  $this->filename = '';
207  $this->writable = false;
208  }
209 
211  function lock() {
212  for($i = 0 ; $i < 20 ; $i++) {
213  if(flock($this->filehandle, 2 + 4))
214  return true;
215  else
216  usleep(250000);
217  }
218  return false;
219  }
220 
222  function unlock() {
223  return flock($this->filehandle, 3);
224  }
225 
232  function overwrite(&$rows) {
233  $this->unlock();
234  $newfh = @fopen($this->filename.'.tmp', 'w');
235 
236  if(!$newfh) {
237  return $this->set_error($this->filename. '.tmp:' . _("Open failed"));
238  }
239 
240  for($i = 0, $cnt=sizeof($rows) ; $i < $cnt ; $i++) {
241  if(is_array($rows[$i])) {
242  for($j = 0, $cnt_part=count($rows[$i]) ; $j < $cnt_part ; $j++) {
243  $rows[$i][$j] = $this->quotevalue($rows[$i][$j]);
244  }
245  $tmpwrite = sq_fwrite($newfh, join('|', $rows[$i]) . "\n");
246  if ($tmpwrite === FALSE) {
247  return $this->set_error($this->filename . '.tmp:' . _("Write failed"));
248  }
249  }
250  }
251 
252  fclose($newfh);
253  if (!@copy($this->filename . '.tmp' , $this->filename)) {
254  return $this->set_error($this->filename . ':' . _("Unable to update"));
255  }
256  @unlink($this->filename . '.tmp');
257  @chmod($this->filename, 0600);
258  $this->unlock();
259  $this->open(true);
260  return true;
261  }
262 
263  /* ========================== Public ======================== */
264 
270  function search($expr) {
271 
272  /* To be replaced by advanded search expression parsing */
273  if(is_array($expr)) { return; }
274 
275  // don't allow wide search when listing is disabled.
276  if ($expr=='*' && ! $this->listing)
277  return array();
278 
279  /* Make regexp from glob'ed expression
280  * May want to quote other special characters like (, ), -, [, ], etc. */
281  $expr = str_replace('?', '.', $expr);
282  $expr = str_replace('*', '.*', $expr);
283 
284  $res = array();
285  if(!$this->open()) {
286  return false;
287  }
288  @rewind($this->filehandle);
289 
290  while ($row = @fgetcsv($this->filehandle, $this->line_length, '|')) {
291  if (count($row)<5) {
293  global $color;
294  error_box(_("Address book is corrupted. Required fields are missing."),$color);
295  die('</body></html>');
296  } else {
297  $line = join(' ', $row);
298  // errors on preg_match call are suppressed in order to prevent display of regexp compilation errors
299  if(@preg_match('/' . $expr . '/i', $line)) {
300  array_push($res, array('nickname' => $row[0],
301  'name' => $row[1] . ' ' . $row[2],
302  'firstname' => $row[1],
303  'lastname' => $row[2],
304  'email' => $row[3],
305  'label' => $row[4],
306  'backend' => $this->bnum,
307  'source' => &$this->sname));
308  }
309  }
310  }
311  return $res;
312  }
313 
330  function lookup($value, $field=SM_ABOOK_FIELD_NICKNAME) {
331  if(empty($value)) {
332  return array();
333  }
334 
335  $value = strtolower($value);
336 
337  $this->open();
338  @rewind($this->filehandle);
339 
340  while ($row = @fgetcsv($this->filehandle, $this->line_length, '|')) {
341  if (count($row)<5) {
343  global $color;
344  error_box(_("Address book is corrupted. Required fields are missing."),$color);
345  die('</body></html>');
346  } else {
347  if(strtolower($row[$field]) == $value) {
348  return array('nickname' => $row[0],
349  'name' => $row[1] . ' ' . $row[2],
350  'firstname' => $row[1],
351  'lastname' => $row[2],
352  'email' => $row[3],
353  'label' => $row[4],
354  'backend' => $this->bnum,
355  'source' => &$this->sname);
356  }
357  }
358  }
359 
360  return array();
361  }
362 
367  function list_addr() {
368  // check if listing is not disabled
369  if(isset($this->listing) && !$this->listing) {
370  return array();
371  }
372 
373  $res = array();
374  $this->open();
375  @rewind($this->filehandle);
376 
377  while ($row = @fgetcsv($this->filehandle, $this->line_length, '|')) {
378  if (count($row)<5) {
380  global $color;
381  error_box(_("Address book is corrupted. Required fields are missing."),$color);
382  die('</body></html>');
383  } else {
384  array_push($res, array('nickname' => $row[0],
385  'name' => $row[1] . ' ' . $row[2],
386  'firstname' => $row[1],
387  'lastname' => $row[2],
388  'email' => $row[3],
389  'label' => $row[4],
390  'backend' => $this->bnum,
391  'source' => &$this->sname));
392  }
393  }
394  return $res;
395  }
396 
402  function add($userdata) {
403  if(!$this->writeable) {
404  return $this->set_error(_("Address book is read-only"));
405  }
406  /* See if user exists already */
407  $ret = $this->lookup($userdata['nickname']);
408  if(!empty($ret)) {
409  // i18n: don't use html formating in translation
410  return $this->set_error(sprintf(_("User \"%s\" already exists"), $ret['nickname']));
411  }
412 
413  /* Here is the data to write */
414  $data = $this->quotevalue($userdata['nickname']) . '|' .
415  $this->quotevalue($userdata['firstname']) . '|' .
416  $this->quotevalue((!empty($userdata['lastname'])?$userdata['lastname']:'')) . '|' .
417  $this->quotevalue($userdata['email']) . '|' .
418  $this->quotevalue((!empty($userdata['label'])?$userdata['label']:''));
419 
420  /* Strip linefeeds */
421  $nl_str = array("\r","\n");
422  $data = str_replace($nl_str, ' ', $data);
423 
428  if (strlen($data) >= $this->line_length) {
429  return $this->set_error(_("Address book entry is too big"));
430  }
431 
432  /* Add linefeed at end */
433  $data = $data . "\n";
434 
435  /* Reopen file, just to be sure */
436  $this->open(true);
437  if(!$this->writeable) {
438  return $this->set_error(_("Address book is read-only"));
439  }
440 
441  /* Lock the file */
442  if(!$this->lock()) {
443  return $this->set_error(_("Could not lock datafile"));
444  }
445 
446  /* Write */
447  $r = sq_fwrite($this->filehandle, $data);
448 
449  /* Unlock file */
450  $this->unlock();
451 
452  /* Test write result */
453  if($r === FALSE) {
454  /* Fail */
455  $this->set_error(_("Write to address book failed"));
456  return FALSE;
457  }
458 
459  return TRUE;
460  }
461 
467  function remove($alias) {
468  if(!$this->writeable) {
469  return $this->set_error(_("Address book is read-only"));
470  }
471 
472  /* Lock the file to make sure we're the only process working
473  * on it. */
474  if(!$this->lock()) {
475  return $this->set_error(_("Could not lock datafile"));
476  }
477 
478  /* Read file into memory, ignoring nicknames to delete */
479  @rewind($this->filehandle);
480  $i = 0;
481  $rows = array();
482  while($row = @fgetcsv($this->filehandle, $this->line_length, '|')) {
483  if(!in_array($row[0], $alias)) {
484  $rows[$i++] = $row;
485  }
486  }
487 
488  /* Write data back */
489  if(!$this->overwrite($rows)) {
490  $this->unlock();
491  return false;
492  }
493 
494  $this->unlock();
495  return true;
496  }
497 
504  function modify($alias, $userdata) {
505  if(!$this->writeable) {
506  return $this->set_error(_("Address book is read-only"));
507  }
508 
509  /* See if user exists */
510  $ret = $this->lookup($alias);
511  if(empty($ret)) {
512  // i18n: don't use html formating in translation
513  return $this->set_error(sprintf(_("User \"%s\" does not exist"), $alias));
514  }
515 
516  /* If the alias changed, see if the new alias exists */
517  if (strtolower($alias) != strtolower($userdata['nickname'])) {
518  $ret = $this->lookup($userdata['nickname']);
519  if (!empty($ret)) {
520  return $this->set_error(sprintf(_("User \"%s\" already exists"), $userdata['nickname']));
521  }
522  }
523 
524  /* calculate userdata size */
525  $data = $this->quotevalue($userdata['nickname']) . '|'
526  . $this->quotevalue($userdata['firstname']) . '|'
527  . $this->quotevalue((!empty($userdata['lastname'])?$userdata['lastname']:'')) . '|'
528  . $this->quotevalue($userdata['email']) . '|'
529  . $this->quotevalue((!empty($userdata['label'])?$userdata['label']:''));
530  /* make sure that it fits into allocated space */
531  if (strlen($data) >= $this->line_length) {
532  return $this->set_error(_("Address book entry is too big"));
533  }
534 
535  /* Lock the file to make sure we're the only process working
536  * on it. */
537  if(!$this->lock()) {
538  return $this->set_error(_("Could not lock datafile"));
539  }
540 
541  /* Read file into memory, modifying the data for the
542  * user identified by $alias */
543  $this->open(true);
544  @rewind($this->filehandle);
545  $i = 0;
546  $rows = array();
547  while($row = @fgetcsv($this->filehandle, $this->line_length, '|')) {
548  if(strtolower($row[0]) != strtolower($alias)) {
549  $rows[$i++] = $row;
550  } else {
551  $rows[$i++] = array(0 => $userdata['nickname'],
552  1 => $userdata['firstname'],
553  2 => (!empty($userdata['lastname'])?$userdata['lastname']:''),
554  3 => $userdata['email'],
555  4 => (!empty($userdata['label'])?$userdata['label']:''));
556  }
557  }
558 
559  /* Write data back */
560  if(!$this->overwrite($rows)) {
561  $this->unlock();
562  return false;
563  }
564 
565  $this->unlock();
566  return true;
567  }
568 
574  function quotevalue($value) {
575  /* Quote the field if it contains | or ". Double quotes need to
576  * be replaced with "" */
577  if(stristr($value, '"') || stristr($value, '|')) {
578  $value = '"' . str_replace('"', '""', $value) . '"';
579  }
580  return $value;
581  }
582 
583 } /* End of class abook_local_file */
SM_ABOOK_FIELD_NICKNAME
const SM_ABOOK_FIELD_NICKNAME
Definition: constants.php:57
$ret
$ret
Definition: webmail.php:172
abook_local_file
Definition: abook_local_file.php:36
$cnt
$cnt
Definition: options_identities.php:86
abook_local_file\search
search($expr)
Definition: abook_local_file.php:270
abook_local_file\$writeable
$writeable
Definition: abook_local_file.php:74
sprintf
powered by Systran sprintf(_("Number of supported language pairs: %s"), '36').' '
Definition: options.php:107
sq_fwrite
sq_fwrite($fp, $string)
Definition: strings.php:763
abook_local_file\abook_local_file
abook_local_file($param)
Definition: abook_local_file.php:101
abook_local_file\$btype
$btype
Definition: abook_local_file.php:41
addressbook_backend\set_error
set_error($string)
Definition: addressbook.php:656
abook_local_file\$detect_writeable
$detect_writeable
Definition: abook_local_file.php:67
abook_local_file\unlock
unlock()
Definition: abook_local_file.php:222
abook_local_file\lookup
lookup($value, $field=SM_ABOOK_FIELD_NICKNAME)
Definition: abook_local_file.php:330
abook_local_file\$umask
$umask
Definition: abook_local_file.php:85
abook_local_file\$listing
$listing
Definition: abook_local_file.php:80
abook_local_file\add
add($userdata)
Definition: abook_local_file.php:402
abook_local_file\open
open($new=false)
Definition: abook_local_file.php:152
abook_local_file\quotevalue
quotevalue($value)
Definition: abook_local_file.php:574
abook_local_file\modify
modify($alias, $userdata)
Definition: abook_local_file.php:504
$r
while(count($Left) > 0) $r
Definition: darkness.php:103
$j
for($i=0; $i< $numboxes; $i++) $j
Definition: empty_trash.php:72
addressbook_backend
Definition: addressbook.php:641
$data
$data
Definition: mailto.php:83
abook_local_file\$create
$create
Definition: abook_local_file.php:62
_
_($str)
Definition: gettext.php:160
abook_local_file\lock
lock()
Definition: abook_local_file.php:211
abook_local_file\close
close()
Definition: abook_local_file.php:203
abook_local_file\list_addr
list_addr()
Definition: abook_local_file.php:367
abook_local_file\$filehandle
$filehandle
Definition: abook_local_file.php:57
$color
$color
Definition: load_prefs.php:28
abook_local_file\$line_length
$line_length
Definition: abook_local_file.php:92
abook_local_file\$filename
$filename
Definition: abook_local_file.php:52
abook_local_file\overwrite
overwrite(&$rows)
Definition: abook_local_file.php:232
abook_local_file\$bname
$bname
Definition: abook_local_file.php:46
error_box
error_box($string, $color)
Definition: display_messages.php:116