class_mail-methods-cyrus.inc 20.9 KB
Newer Older
1
2
3
4
<?php
/*
  This code is part of FusionDirectory (http://www.fusiondirectory.org/)
  Copyright (C) 2003-2010  Cajus Pollmeier
5
  Copyright (C) 2011-2017  FusionDirectory
6
7
8
9
10
11
12
13
14
15
16
17
18

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
19
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
20
21
*/

22
23
24
class mailMethodCyrus extends mailMethod
{
  protected $imap_handle  = NULL;
25
  protected $quota_loaded = FALSE;
26

27
28
29
30
31
32
  /* Allow modification of account_ids for existing mail accounts */
  protected $modifyableMail   = FALSE;

  /* Allow modification of the mail server attribute existing mail accounts */
  protected $modifyableServer = FALSE;

33
  protected $enableQuota            = TRUE;
34
  protected $enableVacationRange    = FALSE;
35
  protected $enableGroupACLs        = TRUE;
36

37
  protected function init ()
38
  {
39
40
41
42
43
44
45
46
47
    $cfg = $this->getServerConfig();

    if (isset($cfg['useSlashes']) && ($cfg['useSlashes'] === 'TRUE')) {
      $this->useSlashesInId = TRUE;
      @DEBUG(DEBUG_MAIL, __LINE__, __FUNCTION__, __FILE__, 'Enabled', '<b>MAIL:</b> cyrusUseSlashes');
    } else {
      @DEBUG(DEBUG_MAIL, __LINE__, __FUNCTION__, __FILE__, 'Disabled', '<b>MAIL:</b> cyrusUseSlashes');
    }

48
    parent::init();
49
50
  }

51
  public function connect ()
52
  {
53
    global $config;
54
    parent::connect();
55
    $this->connected = FALSE;
56

57
58
    $cfg = $this->getServerConfig();
    if ($cfg === FALSE) {
59
60
      return FALSE;
    }
61
62

    /* Setting connect timeout to 10 seconds,
63
        else the FusionDirectory UI may freeze for 60 seconds.
64
       (PHP default is 'default_socket_timeout = 60') */
65
    $timeout = $config->get_cfg_value('imapTimeout', 10);
66
    @DEBUG(DEBUG_MAIL, __LINE__, __FUNCTION__, __FILE__, $timeout,
67
          '<b>IMAP: Setting imap connect timeout to</b> (seconds)');
68
69
70
71
72
    imap_timeout(1, $timeout);

    $this->imap_handle = @imap_open($cfg['connect'], $cfg['admin'], $cfg['password'], OP_HALFOPEN);

    /* Mailbox reachable? */
73
    if ($this->imap_handle === FALSE) {
74
75
      $this->error = imap_last_error();

76
      @DEBUG(DEBUG_MAIL, __LINE__, __FUNCTION__, __FILE__, "<b>Failed</b> :".imap_last_error(),
77
78
        "<b>IMAP:</b> ".$cfg['admin']."@".$cfg['connect']);

Côme Chilliet's avatar
Côme Chilliet committed
79
      return FALSE;
80
    }
81
    @DEBUG(DEBUG_MAIL, __LINE__, __FUNCTION__, __FILE__, "<b>successful</b>",
82
83
84
        "<b>IMAP:</b> ".$cfg['admin']."@".$cfg['connect']);
    $this->connected = TRUE;

85
    return TRUE;
86
87
  }

88
  public function account_exists ()
89
  {
90
    if (!$this->is_connected() || !$this->imap_handle) {
91
      trigger_error('Method not connected, catch error.');
92
      return [];
93
94
95
    }

    /* Get server config */
96
97
98
99
100
    $cfg  = $this->getServerConfig();
    if ($cfg === FALSE) {
      return FALSE;
    }
    $list = @imap_listmailbox($this->imap_handle, $cfg['connect'], $this->account_id);
101
102
    $res  = (is_array($list) && count($list));
    if ($res) {
103
      @DEBUG(DEBUG_MAIL, __LINE__, __FUNCTION__, __FILE__, $this->account_id, '<b>IMAP: Account exists in imap server.</b>');
104
    } else {
105
      @DEBUG(DEBUG_MAIL, __LINE__, __FUNCTION__, __FILE__, $this->account_id, '<b>IMAP: Account seems NOT to exists in imap server.</b>');
106
    }
107
    return $res;
108
109
  }

110
  public function disconnect ()
111
  {
112
    parent::disconnect();
113
    if ($this->is_connected()) {
114
      @imap_close($this->imap_handle);
115
116
117
    }
  }

118
  public function is_connected ()
119
  {
120
    $ret = parent::is_connected();
121
    return ($ret && $this->imap_handle);
122
123
  }

124
  protected function loadQuota ()
125
  {
126
127
128
129
    if (!$this->quotaEnabled()) {
      return TRUE;
    }
    if (!$this->is_connected() || !$this->imap_handle) {
130
      trigger_error("Method not connected, catch error.");
131
      return FALSE;
132
133
134
135
136
    }

    $this->reset_error();

    /* Load quota settings */
137
    $result = ["quotaUsage" => "","gosaMailQuota" => ""];
138
139
140
141
142
143
    $quota_value = @imap_get_quota($this->imap_handle, $this->account_id);

    /* Reset error queue, imap_qet_quota() will fail if the quota wasn't set yet.
     */
    imap_errors();

144
145
    if (is_array($quota_value) && count($quota_value)) {
      if (isset($quota_value["STORAGE"]) && is_array($quota_value["STORAGE"])) {
146
147

        /* use for PHP >= 4.3 */
148
149
150
151
152
153
        if ($quota_value["STORAGE"]['limit'] == 2147483647) {
          $result['quotaUsage']     = (int) ($quota_value["STORAGE"]['usage'] / 1024);
          $result['gosaMailQuota']  = "";
        } else {
          $result['quotaUsage']     = (int) ($quota_value["STORAGE"]['usage'] / 1024);
          $result['gosaMailQuota']  = (int) ($quota_value["STORAGE"]['limit'] / 1024);
154
155
156
157
        }
      } else {

        /* backward icompatible */
158
159
160
161
162
163
        if ($quota_value['usage'] == 2147483647) {
          $result['quotaUsage']     = (int) ($quota_value['usage'] / 1024);
          $result['gosaMailQuota']  = "";
        } else {
          $result['quotaUsage']     = (int) ($quota_value['usage'] / 1024);
          $result['gosaMailQuota']  = (int) ($quota_value['limit'] / 1024);
164
165
166
167
168
169
170
        }
      }
    }
    $this->quotaValue = $result['gosaMailQuota'];
    $this->quotaUsage = $result['quotaUsage'];

    /* Write debug output */
171
172
    if (is_array($quota_value)) {
      if ($this->quotaValue == "") {
173
        $quota = "(".$this->quotaUsage." / unlimited)";
174
      } else {
175
176
        $quota = "(".$this->quotaUsage." / ".$this->quotaValue.")";
      }
177
      @DEBUG(DEBUG_MAIL, __LINE__, __FUNCTION__, __FILE__, $quota,
178
          "<b>IMAP: Successfully received account quota</b>");
179
    } else {
180
      @DEBUG(DEBUG_MAIL, __LINE__, __FUNCTION__, __FILE__, imap_last_error(),
181
182
183
184
          "<b>IMAP: Failed to receive account quota</b>");
    }
  }

185
  public function getQuota ($quota)
186
  {
187
    parent::getQuota($quota);
188
    if (!$this->quota_loaded) {
189
190
191
      $this->quota_loaded = TRUE;
      $this->loadQuota();
    }
192
    return $this->quotaValue;
193
194
  }

195
  public function getQuotaUsage ()
196
  {
197
    parent::getQuotaUsage();
198
    if (!$this->quota_loaded) {
199
200
201
      $this->quota_loaded = TRUE;
      $this->loadQuota();
    }
202
    return $this->quotaUsage;
203
204
  }

205
  public function setQuota ($number)
206
  {
207
    parent::setQuota($number);
208

209
210
211
212
    if (!$this->quotaEnabled()) {
      return TRUE;
    }
    if (!$this->is_connected() || !$this->imap_handle) {
213
      trigger_error("Method not connected, catch error.");
214
      return FALSE;
215
216
217
218
219
    }

    $this->build_account_id();

    /* Workaround for the php imap extension */
220
221
222
223
    if (($this->quotaValue == "") || ($this->quotaValue == "2147483647")) {
      $this->quotaValue = "2147483647";
    } elseif ($this->quotaValue > 0) {
      $this->quotaValue = $this->quotaValue * 1024;
224
225
    }
    $debug_number = $this->quotaValue." KB";
226
    if ($this->quotaValue == "2147483647") {
227
228
229
      $debug_number .= "<i>Unlimited</i>";
    }

230
    if (!imap_set_quota($this->imap_handle, $this->account_id, $this->quotaValue)) {
231
232
      msg_dialog::display(_("IMAP error"), sprintf(_("Cannot modify IMAP mailbox quota: %s"),
            '<br><br><i>'.imap_last_error().'</i>'), ERROR_DIALOG);
233
      @DEBUG(DEBUG_MAIL, __LINE__, __FUNCTION__, __FILE__, "<b>".$this->account_id.": (".$debug_number.")</b>",
234
          "<b>IMAP: Set account quota</b> on server '".$this->parent->gosaMailServer."' <b>".imap_last_error()."</b>");
235
      return FALSE;
236
    }
237
    @DEBUG(DEBUG_MAIL, __LINE__, __FUNCTION__, __FILE__, "<b>".$this->account_id.": (".$debug_number.")</b>",
238
        "<b>IMAP: Set account quota</b> on server :".$this->parent->gosaMailServer);
239
    return TRUE;
240
241
  }

242
  public function updateMailbox ()
243
  {
244
    global $config;
245
    parent::updateMailbox();
246

247
    if (!$this->is_connected() || !$this->imap_handle) {
248
      trigger_error("Method not connected, catch error.");
249
      return FALSE;
250
    }
251

252
    $this->build_account_id();
253

254
    if ($this->is_connected()) {
255
256
257
258
259
      $cfg  = $this->getServerConfig();
      if ($cfg === FALSE) {
        return FALSE;
      }
      $list = imap_listmailbox($this->imap_handle, $cfg['connect'], $this->account_id);
260
      if ($list === FALSE) {
261
        @DEBUG(DEBUG_MAIL, __LINE__, __FUNCTION__, __FILE__, $this->account_id,
262
263
          'IMAP: Add account on server '.$this->parent->gosaMailServer);
        if (!imap_createmailbox($this->imap_handle, $cfg['connect'].$this->account_id)) {
264
          $this->error = imap_last_error();
265
          return FALSE;
266
267
        }

268
        /* Autocreate configured default folders */
269
270
271
272
273
274
        foreach ($cfg['autocreate'] as $folder) {
          @DEBUG(DEBUG_MAIL, __LINE__, __FUNCTION__, __FILE__, $folder,
            'IMAP: Add account folder on server '.$this->parent->gosaMailServer);
          if (!imap_createmailbox($this->imap_handle, $cfg['connect'].$this->create_folder_id($folder))) {
            $this->error = imap_last_error();
            return FALSE;
275
276
277
278
          }
        }
      }
    }
279
    return TRUE;
280
281
  }

282
  public function deleteMailbox ()
283
  {
284
    global $config;
285
    parent::deleteMailbox();
286

287
    if (!$this->is_connected() || !$this->imap_handle) {
288
      trigger_error("Method not connected, catch error.");
289
      return FALSE;
290
291
    }

292
293
294
295
296
    $cfg = $this->getServerConfig();
    if ($cfg === FALSE) {
      return FALSE;
    }

297
    $this->build_account_id();
298

299
    @imap_setacl($this->imap_handle, $this->account_id, $cfg["admin"], "lrswipcda");
300

301
    if ($config->get_cfg_value("cyrusDeleteMailbox", "TRUE") == "TRUE") {
302
      if (!imap_deletemailbox($this->imap_handle, $cfg["connect"].$this->account_id)) {
303
        $this->error = imap_last_error();
304
        return FALSE;
305
      }
306
    } else {
307
308
309
310
      msg_dialog::display(_("Mail info"),
        sprintf(_("LDAP entry has been removed but cyrus mailbox (%s) is kept.\nPlease delete it manually!"),
        $this->account_id), INFO_DIALOG);
    }
311
    return TRUE;
312
313
  }

314
  public function getMailboxList ()
315
  {
316
    if (!$this->is_connected() || !$this->imap_handle) {
317
      trigger_error("Method not connected, catch error.");
318
      return [];
319
320
    }

321
    $result = [];
322

323
324
325
326
    $cfg = $this->getServerConfig();
    if ($cfg === FALSE) {
      return FALSE;
    }
327
328

    /* Create search string
329
330
       And prepare replacements
     */
331
332
333
334
335
336
337
338
339
    if (preg_match("/\@/", $this->account_id)) {
      if ($this->cyrusUseSlashes) {
        $search = preg_replace("/\@/", "/*@", $this->account_id);
      } else {
        $search = preg_replace("/\@/", ".*@", $this->account_id);
      }
      $with_domain = TRUE;
    } else {
      if ($this->cyrusUseSlashes) {
340
        $search = $this->account_id."/*";
341
      } else {
342
343
        $search = $this->account_id.".*";
      }
344
345
346
      $with_domain = FALSE;
    }
    $folder = $this->account_id;
347
348
    if (preg_match("/\@/", $folder)) {
      $folder = preg_replace("/\@.*$/", "", $folder);
349
350
351
    }

    /* Contact imap server */
352
353
    $list   = @imap_listmailbox($this->imap_handle, $cfg["connect"], $this->account_id);
    $list2  = @imap_listmailbox($this->imap_handle, $cfg["connect"], $search);
354
355

    /* Create list of returned folder names */
356
    if (is_array($list)) {
357
358

      /* Merge in subfolders */
359
360
      if (is_array($list2)) {
        $list = array_merge($list, $list2);
361
362
      }

363
364
365
366
      foreach ($list as $val) {
        $str = trim(preg_replace("/^\{[^\}]*+\}/", "", $val));
        if ($with_domain) {
          $str = trim(preg_replace("/\@.*$/", "", $str));
367
        }
368
        $str = preg_replace("/^.*".preg_quote($folder, '/')."/", "INBOX",
369
          mb_convert_encoding($str, "UTF-8", "UTF7-IMAP"));
370
        $result[] = $str;
371
      }
372
      @DEBUG(DEBUG_MAIL, __LINE__, __FUNCTION__, __FILE__, trim(implode($result, ", "), ", "),
373
374
          "<b>IMAP: Received mailbox folders.</b>");
      $this->error = imap_last_error();
375
    } else {
376
      @DEBUG(DEBUG_MAIL, __LINE__, __FUNCTION__, __FILE__, imap_last_error(),
377
378
          "<b>IMAP: Cannot receive mailbox folders.</b>");
      $this->error = imap_last_error();
379
      return [];
380
381
382
    }

    /* Append "INBOX" to the folder array if result is empty and request comes from user dialog */
383
    if (!count($result)) {
384
385
386
      $result[] = "INBOX";
    }

387
    return $result;
388
389
390
391
  }

  /*! \brief  Returns configured acls
   */
392
  public function getFolderACLs (): array
393
394
395
  {
    $this->reset_error();

396
397
398
399
400
    if (!$this->is_connected() || !$this->imap_handle) {
      trigger_error("Method not connected, catch error.");
      return [];
    }

401
    /* imap_getacl available? */
402
    if (!function_exists('imap_getacl')) {
403
404
405
406
      $this->error = _('The module imap_getacl is not implemented!');
      @DEBUG(DEBUG_MAIL, __LINE__, __FUNCTION__, __FILE__, 'The imap_getacl module is missing!',
          '<b>IMAP: Cannot set folder acls</b>');
      return [];
407
408
    }

409
    /* Get ACLs */
410
    $this->build_account_id();
411
    $acls = imap_getacl($this->imap_handle, $this->account_id);
412

413
    foreach ($acls as &$acl) {
414
      $acl = $this->expandAndSortACL($acl);
415
      if (!isset($this->acl_mapping[$acl])) {
416
417
418
        /* Merge given ACL with acl mapping
           This ensures that no ACL will accidentally be overwritten
         */
419
420
421
        $this->acl_mapping[$acl] = $acl;
      }
    }
422
423
424
425
426
    unset($acl);

    if (!isset($acls['anyone'])) {
      $acls['anyone'] = '';
    }
427

428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
    return $acls;
  }

  /*! \brief Put ACLs rights always in the same order and expand legacy rights
   */
  protected function expandAndSortACL (string $acl): string
  {
    $letters = 'lrswipkxtea';
    if (strpos($acl, 'c') !== FALSE) {
      /* Expand c to kx */
      $acl .= 'kx';
    }
    if (strpos($acl, 'd') !== FALSE) {
      /* Expand d to xte */
      $acl .= 'xte';
    }
    $res = '';
    foreach (str_split($letters) as $letter) {
      if (strpos($acl, $letter) !== FALSE) {
        $res .= $letter;
      }
    }

    return $res;
452
453
454
455
  }

  /*! \brief  Write ACLs back to imap or what ever
   */
456
  public function setFolderACLs (array $acls): bool
457
458
459
460
  {
    $this->reset_error();

    /* imap_getacl available? */
461
    if (!function_exists('imap_getacl')) {
462
      $this->error = _("The module imap_getacl is not implemented!");
463
      @DEBUG(DEBUG_MAIL, __LINE__, __FUNCTION__, __FILE__, "The imap_getacl module is missing!",
464
          "<b>IMAP: Cannot set folder acls.</b>");
465
      return FALSE;
466
467
    }

468
469
    $this->build_account_id();

470
    /* Get list of subfolders */
471
472
    $folders = $this->getMailboxList();
    foreach ($folders as $subfolder) {
473
474
475
      $folder_id = $this->create_folder_id($subfolder);

      /* Remove all acl's for this folder */
476
      $users = @imap_getacl($this->imap_handle, $folder_id);
477

478
479
      if (is_array($users)) {
        foreach ($users as $userid => $perms) {
480
          $userid = strtolower($userid);
481
482
          imap_setacl($this->imap_handle, $folder_id, $userid, "");
          @DEBUG(DEBUG_MAIL, __LINE__, __FUNCTION__, __FILE__, $folder_id." -> ".$userid,
483
484
485
486
487
488
              "<b>IMAP: Removing folder permissions.</b>");
        }
      }
    }

    /* Set permissions for this folder */
489
    foreach ($folders as $subfolder) {
490
491
      $folder_id = $this->create_folder_id($subfolder);

492
      foreach ($acls as $user => $acl) {
493
494
        imap_setacl($this->imap_handle, $folder_id, $user, $acl);
        @DEBUG(DEBUG_MAIL, __LINE__, __FUNCTION__, __FILE__, $folder_id." -> ".$user.": ".$acl,
495
496
497
            "<b>IMAP: Setting new folder permissions.</b>");
      }
    }
498
    return TRUE;
499
500
  }

501
  public function saveSieveSettings ()
502
  {
503
    parent::saveSieveSettings();
504

505
    /* Map attribute from parent class
506
     */
507
508
    $mail                     = $this->parent->mail;
    $gosaMailDeliveryMode     = $this->parent->gosaMailDeliveryMode;
509
    $gosaMailAlternateAddress = $this->parent->gosaMailAlternateAddress;
510
    $gosaVacationMessage      = $this->parent->gosaVacationMessage;
511
512

    /* Try to login into sieve
513
     */
514
515
516
517
    $cfg    = $this->getServerConfig();
    if ($cfg === FALSE) {
      return FALSE;
    }
518
519
    $sieve  = new sieve($cfg["sieve_server"], $cfg["sieve_port"], $cfg["admin"],
                        $cfg["password"], $this->getUAttribValue(), $cfg["sieve_option"]);
520
    if (!$sieve->sieve_login()) {
521
      @DEBUG(DEBUG_MAIL, __LINE__, __FUNCTION__, __FILE__, $sieve->error_raw, "<b>SIEVE: login failed.</b>");
522
      $this->error = $sieve->error_raw;
523
      return FALSE;
524
525
    }

526
527
    /* Get current sieve script named 'fusiondirectory'.
        Check if it valid ("###FUSIONDIRECTORY" must be the first string).
528
        If it is valid just replace it, if it is NOT valid
529
         create a backup of the old
530
     */
531
    if ($sieve->sieve_listscripts()) {
532
533
534
535
      if (in_array('fusiondirectory', $sieve->response)) {
        $script = "";
        if (!$sieve->sieve_getscript('fusiondirectory')) {
          $this->error = sprintf(_('Cannot retrieve SIEVE script: %s'), to_string($sieve->error_raw));
536
          @DEBUG(DEBUG_MAIL, __LINE__, __FUNCTION__, __FILE__, $sieve->error_raw,
537
              "<b>SIEVE: Cannot read 'fusiondirectory' sieve script.</b>");
538
          return FALSE;
539
540
541
        }

        $is_valid_script = FALSE;
542
543
544
545
        foreach ($sieve->response as $line) {
          if (empty($line)) {
            continue;
          }
546
          if (preg_match('/^###FUSIONDIRECTORY/', $line) && strlen($script) == 0) {
547
548
            $is_valid_script = TRUE;
          }
549
          $line   = rtrim($line);
550
551
552
          $script .= $line;
        }

553
        if ($is_valid_script || strlen($script) == 0 || empty($script)) {
554
          @DEBUG(DEBUG_MAIL, __LINE__, __FUNCTION__, __FILE__, "",
555
              "<b>SIEVE</b>: Sieve script 'fusiondirectory' was a valid FusionDirectory script and will be replaced.");
556
        } else {
557
          $new_name = "non_fusiondirectory_".date("Ymd_H-i-s");
558
          $sieve->sieve_sendscript($new_name, $script);
559
          @DEBUG(DEBUG_MAIL, __LINE__, __FUNCTION__, __FILE__, $this->sieve->error_raw,
560
              "<b>SIEVE</b>: Non FusionDirectory sieve script. <b>Creating backup of the current sieve script '".$new_name."'.</b>");
561
562
563
564
565
566
567
568
569
570
        }
      }
    }


    /*****
      Build up new sieve script here.
     *****/

    /* Only create a new one, if it is not empty */
571
    $smarty = get_smarty();
572
    if (is_integer(strpos($gosaMailDeliveryMode, "C")) ||
573
        is_integer(strpos($gosaMailDeliveryMode, "I")) ||
574
        is_integer(strpos($gosaMailDeliveryMode, "V"))) {
Mortier Benoit's avatar
Mortier Benoit committed
575

576
577
578
579
580
581
582
583
584
585
586
587
      /* Add vacation information */
      $smarty->assign('vacation', is_integer(strpos($gosaMailDeliveryMode, "V")));
      if (is_integer(strpos($gosaMailDeliveryMode, "V"))) {
        /* Sieve wants all destination addresses for the
           vacation message, so we've to assemble them from
           mail and mailAlternateAddress */
        $addrlist = '"'.$mail.'"';
        foreach ($gosaMailAlternateAddress as $val) {
          $addrlist .= ", \"$val\"";
        }
        $smarty->assign('addrlist', $addrlist);
        $smarty->assign('vacmsg', addslashes(addslashes($gosaVacationMessage)));
588
589
      }

590
591
      /* If no local delivery is wanted, tell the script to discard the mail */
      $smarty->assign('dropownmail', is_integer(strpos($gosaMailDeliveryMode, "I")));
592

593
594
595
596
      $script = $smarty->fetch(get_template_path('sieve_script.tpl', TRUE, dirname(__FILE__)));
    } else {
      $script = '';
    }
597
598
599
600
601
    /****
      Sieve script build complete
     ****/

    /* Upload script and make it the default one */
602
    if (!$sieve->sieve_sendscript("fusiondirectory", $script)) {
603
      $this->error = sprintf(_("Cannot store SIEVE script: %s"), to_string($sieve->error_raw));
604
      @DEBUG(DEBUG_MAIL, __LINE__, __FUNCTION__, __FILE__, "Error was: ".to_string($sieve->error_raw),
605
        "<b>SIEVE: Writing new Sieve script failed!</b>");
606
      return FALSE;
607
608
    }

609
    if (!$sieve->sieve_setactivescript("fusiondirectory")) {
610
      $this->error = sprintf(_("Cannot activate SIEVE script: %s"), to_string($sieve->error_raw));
611
      return FALSE;
612
613
614
    }

    $sieve->sieve_logout();
615
    return TRUE;
616
  }
617

618
  static public function get_server_list ()
619
  {
620
    global $config;
621
    $serverList = [];
622

623
624
    $ldap = $config->get_ldap_link();
    $ldap->cd($config->current['BASE']);
625
    $ldap->search('(objectClass=fdCyrusServer)',
626
627
628
629
                  [
                    'cn','fdCyrusConnect','fdCyrusAdmin','fdCyrusPassword',
                    'fdCyrusSieveServer','fdCyrusUseSlashes','fdCyrusAutocreateFolders'
                  ]);
630
    while ($attrs = $ldap->fetch()) {
631
      sscanf($attrs['fdCyrusSieveServer'][0], '{%[^{}:]:%d/%[^{}]}', $sieve_server, $sieve_port, $sieve_option);
632

633
      $serverList[$attrs['cn'][0]] = [
634
635
636
637
638
        'server_dn'     => $attrs['dn'],
        'connect'       => $attrs['fdCyrusConnect'][0],
        'admin'         => $attrs['fdCyrusAdmin'][0],
        'password'      => $attrs['fdCyrusPassword'][0],
        'useSlashes'    => ($attrs['fdCyrusUseSlashes'][0] ?? 'FALSE'),
639
        'autocreate'    => ($attrs['fdCyrusAutocreateFolders'] ?? []),
640
641
642
        'sieve_server'  => $sieve_server,
        'sieve_option'  => $sieve_option,
        'sieve_port'    => $sieve_port
643
      ];
644
645
646
647
    }

    return $serverList;
  }
648
}