~ubuntu-branches/ubuntu/hardy/squirrelmail/hardy-updates

« back to all changes in this revision

Viewing changes to functions/abook_local_file.php

  • Committer: Bazaar Package Importer
  • Author(s): Sam Johnston
  • Date: 2004-02-04 01:42:12 UTC
  • Revision ID: james.westby@ubuntu.com-20040204014212-ek9533qvd2vo1wa1
Tags: upstream-1.5.0
ImportĀ upstreamĀ versionĀ 1.5.0

Show diffs side-by-side

added added

removed removed

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