diff --git a/plugins/calendar/drivers/kolab/kolab_calendar.php b/plugins/calendar/drivers/kolab/kolab_calendar.php
--- a/plugins/calendar/drivers/kolab/kolab_calendar.php
+++ b/plugins/calendar/drivers/kolab/kolab_calendar.php
@@ -402,7 +402,7 @@
                 foreach ($event['attendees'] as $attendee) {
                     if (
                         in_array($attendee['email'], $user_emails)
-                        && in_array($attendee['status'], $partstat_exclude)
+                        && in_array($attendee['status'] ?? null, $partstat_exclude)
                     ) {
                         return false;
                     }
diff --git a/plugins/calendar/drivers/kolab/kolab_driver.php b/plugins/calendar/drivers/kolab/kolab_driver.php
--- a/plugins/calendar/drivers/kolab/kolab_driver.php
+++ b/plugins/calendar/drivers/kolab/kolab_driver.php
@@ -180,7 +180,7 @@
 
             $parents[] = $cal->id;
 
-            if ($cal->virtual) {
+            if (property_exists($cal, "virtual") && $cal->virtual) {
                 $calendars[$cal->id] = [
                     'id'       => $cal->id,
                     'name'     => $cal->get_name(),
diff --git a/plugins/kolab_activesync/kolab_activesync_ui.php b/plugins/kolab_activesync/kolab_activesync_ui.php
--- a/plugins/kolab_activesync/kolab_activesync_ui.php
+++ b/plugins/kolab_activesync/kolab_activesync_ui.php
@@ -125,23 +125,23 @@
         }
 
         $devicetype = strtolower($this->device['TYPE']);
-        $device_force_subscriptions = $this->force_subscriptions[$devicetype];
+        $device_force_subscriptions = $this->force_subscriptions[$devicetype] ?? null;
 
         foreach ($this->plugin->list_folders() as $folder) {
-            if ($folder_types[$folder]) {
+            if ($folder_types[$folder] ?? null) {
                 list($type, ) = explode('.', $folder_types[$folder]);
             }
             else {
                 $type = 'mail';
             }
 
-            if (is_array($folder_groups[$type])) {
+            if (is_array($folder_groups[$type] ?? null)) {
                 $folder_groups[$type][] = $folder;
 
                 if ($device_force_subscriptions && array_key_exists($folder, $device_force_subscriptions)) {
-                    $subscribed[$folder] = intval($device_force_subscriptions[$folder]);
-                } else if (!empty($folder_meta) && ($meta = $folder_meta[$folder])
-                    && $meta['FOLDER'] && $meta['FOLDER'][$imei]['S']
+                    $subscribed[$folder] = intval($device_force_subscriptions[$folder] ?? null);
+                } else if (!empty($folder_meta) && ($meta = ($folder_meta[$folder] ?? null))
+                    && ($meta['FOLDER'] ?? false) && $meta['FOLDER'][$imei]['S']
                 ) {
                     $subscribed[$folder] = intval($meta['FOLDER'][$imei]['S']);
                 }
@@ -149,6 +149,7 @@
         }
 
         // build block for every folder type
+        $html = null;
         foreach ($folder_groups as $type => $group) {
             if (empty($group)) {
                 continue;
@@ -181,7 +182,7 @@
                 'title'    => $this->plugin->gettext('synchronize'),
                 'tabindex' => 0
             ),
-            $attrib['syncicon'] ? html::img(array('src' => $this->skin_path . $attrib['syncicon'])) :
+            ($attrib['syncicon'] ?? false) ? html::img(array('src' => $this->skin_path . $attrib['syncicon'])) :
                 $this->plugin->gettext('synchronize')
         );
 
@@ -191,7 +192,7 @@
                     'title'    => $this->plugin->gettext('withalarms'),
                     'tabindex' => 0
                 ),
-                $attrib['alarmicon'] ? html::img(array('src' => $this->skin_path . $attrib['alarmicon'])) :
+                ($attrib['alarmicon'] ?? null) ? html::img(array('src' => $this->skin_path . $attrib['alarmicon'])) :
                     $this->plugin->gettext('withalarms')
             );
         }
@@ -237,7 +238,7 @@
 
             if ($alarms) {
                 $table->add('alarm checkbox-cell', $checkbox_alarm->show(
-                    intval($subscribed[$folder]) > 1 ? $folder : null,
+                    intval($subscribed[$folder] ?? 0) > 1 ? $folder : null,
                     array('value' => $folder, 'id' => $folder_id.'_alarm', 'disabled' => $disabled)));
             }
 
diff --git a/plugins/kolab_addressbook/drivers/kolab/kolab_contacts.php b/plugins/kolab_addressbook/drivers/kolab/kolab_contacts.php
--- a/plugins/kolab_addressbook/drivers/kolab/kolab_contacts.php
+++ b/plugins/kolab_addressbook/drivers/kolab/kolab_contacts.php
@@ -166,7 +166,7 @@
 
         // set localized labels for proprietary cols
         foreach ($this->coltypes as $col => $prop) {
-            if (is_string($prop['label'])) {
+            if (is_string($prop['label'] ?? null)) {
                 $this->coltypes[$col]['label'] = $rcube->gettext($prop['label']);
             }
         }
@@ -1320,10 +1320,10 @@
      */
     private function _from_rcube_contact($contact, $old = array())
     {
-        if (!$contact['uid'] && $contact['ID']) {
+        if (!($contact['uid'] ?? null) && ($contact['ID'] ?? null)) {
             $contact['uid'] = $this->id2uid($contact['ID']);
         }
-        else if (!$contact['uid'] && $old['uid']) {
+        else if (!($contact['uid'] ?? null) && ($old['uid'] ?? null)) {
             $contact['uid'] = $old['uid'];
         }
 
@@ -1368,7 +1368,7 @@
         $contact['address'] = $addresses;
 
         // categories are not supported in the web client but should be preserved (#2608)
-        $contact['categories'] = $old['categories'];
+        $contact['categories'] = $old['categories'] ?? null;
 
         // copy meta data (starting with _) from old object
         foreach ((array)$old as $key => $val) {
@@ -1380,7 +1380,7 @@
         // convert one-item-array elements into string element
         // this is needed e.g. to properly import birthday field
         foreach ($this->coltypes as $type => $col_def) {
-            if ($col_def['limit'] == 1 && is_array($contact[$type])) {
+            if (($col_def['limit'] ?? null) == 1 && is_array($contact[$type] ?? null)) {
                 $contact[$type] = array_shift(array_filter($contact[$type]));
             }
         }
diff --git a/plugins/kolab_addressbook/drivers/kolab/kolab_contacts_driver.php b/plugins/kolab_addressbook/drivers/kolab/kolab_contacts_driver.php
--- a/plugins/kolab_addressbook/drivers/kolab/kolab_contacts_driver.php
+++ b/plugins/kolab_addressbook/drivers/kolab/kolab_contacts_driver.php
@@ -242,7 +242,7 @@
      */
     public function abook_prop($id, $abook)
     {
-        if ($abook->virtual) {
+        if (property_exists($abook, 'virtual') && $abook->virtual) {
             return [
                 'id'       => $id,
                 'name'     => $abook->get_name(),
diff --git a/plugins/kolab_addressbook/kolab_addressbook.php b/plugins/kolab_addressbook/kolab_addressbook.php
--- a/plugins/kolab_addressbook/kolab_addressbook.php
+++ b/plugins/kolab_addressbook/kolab_addressbook.php
@@ -471,7 +471,7 @@
     public function contact_form($p)
     {
         // none of our business
-        if (!is_object($GLOBALS['CONTACTS']) || !is_a($GLOBALS['CONTACTS'], 'kolab_contacts')) {
+        if (!is_object($GLOBALS['CONTACTS'] ?? null) || !is_a($GLOBALS['CONTACTS'], 'kolab_contacts')) {
             return $p;
         }
 
diff --git a/plugins/kolab_auth/kolab_auth.php b/plugins/kolab_auth/kolab_auth.php
--- a/plugins/kolab_auth/kolab_auth.php
+++ b/plugins/kolab_auth/kolab_auth.php
@@ -61,7 +61,7 @@
 
         // Hook to modify logging directory
         $this->add_hook('write_log', array($this, 'write_log'));
-        $this->username = $_SESSION['username'];
+        $this->username = $_SESSION['username'] ?? null;
 
         // Enable debug logs (per-user), when logged as another user
         if (!empty($_SESSION['kolab_auth_admin']) && $rcmail->config->get('kolab_auth_auditlog')) {
@@ -666,7 +666,7 @@
         foreach ((array)$email_attr as $field) {
             $email = is_array($record[$field]) ? array_filter($record[$field]) : $record[$field];
             if (!empty($email)) {
-                $this->data['user_email'] = array_merge((array)$this->data['user_email'], (array)$email);
+                $this->data['user_email'] = array_merge((array)($this->data['user_email'] ?? null), (array)$email);
             }
         }
         // Organization name for identity (first log in)
diff --git a/plugins/kolab_files/lib/kolab_files_engine.php b/plugins/kolab_files/lib/kolab_files_engine.php
--- a/plugins/kolab_files/lib/kolab_files_engine.php
+++ b/plugins/kolab_files/lib/kolab_files_engine.php
@@ -31,6 +31,7 @@
     private $timeout = 600;
     private $files_sort_cols    = array('name', 'mtime', 'size');
     private $sessions_sort_cols = array('name');
+    private $mimetypes = null;
 
     const API_VERSION = 4;
 
@@ -55,6 +56,7 @@
         $this->plugin->add_texts('localization/');
 
         $templates = array();
+        $list_widget = false;
 
         // set templates of Files UI and widgets
         if ($this->rc->task == 'mail') {
@@ -140,7 +142,7 @@
         $this->rc->output->set_env('files_url', $this->url . '/api/');
         $this->rc->output->set_env('files_token', $this->get_api_token());
         $this->rc->output->set_env('files_caps', $caps);
-        $this->rc->output->set_env('files_api_version', $caps['VERSION'] ?: 3);
+        $this->rc->output->set_env('files_api_version', $caps['VERSION'] ?? 3);
         $this->rc->output->set_env('files_user', $this->rc->get_user_name());
 
         if ($caps['DOCEDIT']) {
@@ -921,7 +923,7 @@
      */
     public function quota_display($attrib)
     {
-        if (!$attrib['id']) {
+        if (!($attrib['id'] ?? false)) {
             $attrib['id'] = 'rcmquotadisplay';
         }
 
@@ -1076,7 +1078,7 @@
     {
         $url = $this->url_srv . '/api/';
 
-        if (!$this->request) {
+        if (!property_exists($this, "request") || !$this->request) {
             $config = array(
                 'store_body'       => true,
                 'follow_redirects' => true,
@@ -1176,8 +1178,8 @@
         $this->rc->output->set_env('file_mimetypes', $this->get_mimetypes());
         $this->rc->output->set_env('files_quota', $caps['QUOTA']);
         $this->rc->output->set_env('files_max_upload', $caps['MAX_UPLOAD']);
-        $this->rc->output->set_env('files_progress_name', $caps['PROGRESS_NAME']);
-        $this->rc->output->set_env('files_progress_time', $caps['PROGRESS_TIME']);
+        $this->rc->output->set_env('files_progress_name', $caps['PROGRESS_NAME'] ?? null);
+        $this->rc->output->set_env('files_progress_time', $caps['PROGRESS_TIME'] ?? null);
         $this->rc->output->send('kolab_files.files');
     }
 
diff --git a/plugins/kolab_folders/kolab_folders.php b/plugins/kolab_folders/kolab_folders.php
--- a/plugins/kolab_folders/kolab_folders.php
+++ b/plugins/kolab_folders/kolab_folders.php
@@ -42,6 +42,7 @@
     private $rc;
     private static $instance;
     private $expire_annotation = '/shared/vendor/cmu/cyrus-imapd/expire';
+    private $is_processing = false;
 
 
     /**
@@ -158,7 +159,7 @@
 
         // Add type-based style for table rows
         // See kolab_folders::folder_class_name()
-        if ($table = $args['table']) {
+        if ($table = ($args['table'] ?? null)) {
             for ($i=1, $cnt=$table->size(); $i<=$cnt; $i++) {
                 $attrib = $table->get_row_attribs($i);
                 $folder = $attrib['foldername']; // UTF7-IMAP
@@ -175,10 +176,10 @@
         }
 
         // Add type-based class for list items
-        if (is_array($args['list'])) {
+        if (is_array($args['list'] ?? null)) {
             foreach ((array)$args['list'] as $k => $item) {
                 $folder = $item['folder_imap']; // UTF7-IMAP
-                $type   = $folderdata[$folder];
+                $type   = $folderdata[$folder] ?? null;
 
                 if (!$type) {
                     $type = 'mail';
@@ -286,7 +287,7 @@
             $sub_types[$ftype] = array_combine($subtypes, array_map(array($this, 'gettext'), $subtypes));
 
             // fill options for the current folder type
-            if ($ftype == $ctype || $ftype == $new_ctype) {
+            if ($ftype == $ctype || (isset($new_ctype) && $ftype == $new_ctype)) {
                 $sub_select->add(array_values($sub_types[$ftype]), $subtypes);
             }
         }
@@ -596,7 +597,7 @@
      */
     static function folder_class_name($type)
     {
-        list($ctype, $subtype) = explode('.', $type);
+        list($ctype, $subtype) = array_pad(explode('.', $type), 2, null);
 
         $class[] = 'type-' . ($ctype ? $ctype : 'mail');
 
@@ -744,7 +745,7 @@
         $value = $storage->get_metadata($folder, $this->expire_annotation);
 
         if (is_array($value)) {
-            return $value[$folder] ? intval($value[$folder][$this->expire_annotation]) : 0;
+            return ($value[$folder] ?? false) ? intval($value[$folder][$this->expire_annotation]) : 0;
         }
 
         return false;
diff --git a/plugins/kolab_notes/kolab_notes.php b/plugins/kolab_notes/kolab_notes.php
--- a/plugins/kolab_notes/kolab_notes.php
+++ b/plugins/kolab_notes/kolab_notes.php
@@ -540,7 +540,7 @@
 
         // deliver from in-memory cache
         $key = $list_id . ':' . $uid;
-        if ($this->cache[$key]) {
+        if ($this->cache[$key] ?? false) {
             return $this->cache[$key];
         }
 
@@ -732,7 +732,7 @@
             return false;
 
         // moved from another folder
-        if ($note['_fromlist'] && ($fromfolder = $this->get_folder($note['_fromlist']))) {
+        if (($note['_fromlist'] ?? false) && ($fromfolder = $this->get_folder($note['_fromlist']))) {
             if (!$fromfolder->move($note['uid'], $folder->name))
                 return false;
 
@@ -740,6 +740,7 @@
         }
 
         // load previous version of this record to merge
+        $old = null;
         if ($note['uid']) {
             $old = $folder->get_object($note['uid']);
             if (!$old || PEAR::isError($old))
@@ -754,8 +755,8 @@
         $object = $this->_write_preprocess($note, $old);
 
         // email links and tags are handled separately
-        $links = $object['links'];
-        $tags  = $object['tags'];
+        $links = $object['links'] ?? null;
+        $tags  = $object['tags'] ?? null;
 
         unset($object['links']);
         unset($object['tags']);
@@ -1372,7 +1373,9 @@
             $object['links'] = array_map(function($link){ return is_array($link) ? $link['uri'] : strval($link); }, $note['links']);
         }
         else {
-            $object['links'] = $old['links'];
+            if ($old) {
+                $object['links'] = $old['links'] ?? null;
+            }
         }
 
         // clean up HTML content
@@ -1404,7 +1407,7 @@
         }
 
         // make list of categories unique
-        if (is_array($object['tags'])) {
+        if (is_array($object['tags'] ?? null)) {
             $object['tags'] = array_unique(array_filter($object['tags']));
         }
 
diff --git a/plugins/kolab_notes/kolab_notes_ui.php b/plugins/kolab_notes/kolab_notes_ui.php
--- a/plugins/kolab_notes/kolab_notes_ui.php
+++ b/plugins/kolab_notes/kolab_notes_ui.php
@@ -77,12 +77,12 @@
     {
         $attrib += array('id' => 'rcmkolabnotebooks');
 
-        if ($attrib['type'] == 'select') {
+        if (($attrib['type'] ?? null) == 'select') {
             $attrib['is_escaped'] = true;
             $select = new html_select($attrib);
         }
 
-        $tree = $attrib['type'] != 'select' ? true : null;
+        $tree = ($attrib['type'] ?? null) != 'select' ? true : null;
         $lists = $this->plugin->get_lists($tree);
         $jsenv = array();
 
@@ -115,7 +115,7 @@
         $this->rc->output->set_env('kolab_notebooks', $jsenv);
         $this->rc->output->add_gui_object('notebooks', $attrib['id']);
 
-        return $attrib['type'] == 'select' ? $select->show() : html::tag('ul', $attrib, $html, html::$common_attrib);
+        return ($attrib['type'] ?? null) == 'select' ? $select->show() : html::tag('ul', $attrib, $html, html::$common_attrib);
     }
 
     /**
@@ -139,7 +139,7 @@
             if (strlen($content)) {
                 $out .= html::tag('li', array(
                       'id' => 'rcmliknb' . rcube_utils::html_identifier($id),
-                      'class' => $prop['group'] . ($prop['virtual'] ? ' virtual' : ''),
+                      'class' => $prop['group'] . (($prop['virtual'] ?? false) ? ' virtual' : ''),
                     ),
                     $content);
             }
@@ -153,13 +153,13 @@
      */
     public function folder_list_item($id, $prop, &$jsenv, $checkbox = false)
     {
-        if (!$prop['virtual']) {
+        if (!($prop['virtual'] ?? false)) {
             unset($prop['user_id']);
             $jsenv[$id] = $prop;
         }
 
         $classes = array('folder');
-        if ($prop['virtual']) {
+        if ($prop['virtual'] ?? false) {
             $classes[] = 'virtual';
         }
         else if (!$prop['editable']) {
@@ -172,14 +172,14 @@
             $classes[] = $prop['class'];
         }
 
-        $title = $prop['title'] ?: ($prop['name'] != $prop['listname'] || strlen($prop['name']) > 25 ?
+        $title = $prop['title'] ?? ($prop['name'] != $prop['listname'] || strlen($prop['name']) > 25 ?
           html_entity_decode($prop['name'], ENT_COMPAT, RCUBE_CHARSET) : '');
 
         $label_id = 'nl:' . $id;
-        $attr = $prop['virtual'] ? array('tabindex' => '0') : array('href' => $this->rc->url(array('_list' => $id)));
+        $attr = ($prop['virtual'] ?? false) ? array('tabindex' => '0') : array('href' => $this->rc->url(array('_list' => $id)));
         return html::div(join(' ', $classes),
             html::a($attr + array('class' => 'listname', 'title' => $title, 'id' => $label_id), $prop['listname'] ?: $prop['name']) .
-            ($prop['virtual'] ? '' :
+            (($prop['virtual'] ?? false) ? '' :
                 ($checkbox ?
                     html::tag('input', array('type' => 'checkbox', 'name' => '_list[]', 'value' => $id, 'checked' => $prop['active'], 'aria-labelledby' => $label_id)) :
                     ''
diff --git a/plugins/kolab_tags/lib/kolab_tags_engine.php b/plugins/kolab_tags/lib/kolab_tags_engine.php
--- a/plugins/kolab_tags/lib/kolab_tags_engine.php
+++ b/plugins/kolab_tags/lib/kolab_tags_engine.php
@@ -484,7 +484,7 @@
         $result = array(
             'uid'   => $tag['uid'],
             'name'  => $tag['name'],
-            'color' => $tag['color'],
+            'color' => $tag['color'] ?? null,
         );
 
         if ($list) {
diff --git a/plugins/libcalendaring/libcalendaring.php b/plugins/libcalendaring/libcalendaring.php
--- a/plugins/libcalendaring/libcalendaring.php
+++ b/plugins/libcalendaring/libcalendaring.php
@@ -146,7 +146,7 @@
             );
         }
 
-        if ($args['task'] == 'mail') {
+        if (($args['task'] ?? null) == 'mail') {
             if ($args['action'] == 'show' || $args['action'] == 'preview') {
                 $this->add_hook('message_load', array($this, 'mail_message_load'));
             }
diff --git a/plugins/libkolab/lib/kolab_format.php b/plugins/libkolab/lib/kolab_format.php
--- a/plugins/libkolab/lib/kolab_format.php
+++ b/plugins/libkolab/lib/kolab_format.php
@@ -417,7 +417,7 @@
     protected function update_uid()
     {
         // get generated UID
-        if (!$this->data['uid']) {
+        if (!($this->data['uid'] ?? null)) {
             if ($this->xmlobject) {
                 $this->data['uid'] = $this->xmlobject->getSerializedUID();
             }
@@ -547,7 +547,7 @@
         // set some automatic values if missing
         if (method_exists($this->obj, 'setCreated')) {
             // Always set created date to workaround libkolabxml (>1.1.4) bug
-            $created = $object['created'] ?: new DateTime('now');
+            $created = $object['created'] ?? new DateTime('now');
             $created->setTimezone(new DateTimeZone('UTC')); // must be UTC
             $this->obj->setCreated(self::get_datetime($created));
             $object['created'] = $created;
@@ -611,7 +611,7 @@
         if ($data) {
             foreach ($data as $idx => $value) {
                 if (is_array($value)) {
-                    $object[$idx] = array_merge((array)$object[$idx], $value);
+                    $object[$idx] = array_merge((array)($object[$idx] ?? []), $value);
                 }
                 else {
                     $object[$idx] = $value;
@@ -698,7 +698,7 @@
     {
         // save attachments
         $vattach = new vectorattachment;
-        foreach ((array) $object['_attachments'] as $cid => $attr) {
+        foreach ((array)($object['_attachments'] ?? []) as $cid => $attr) {
             if (empty($attr))
                 continue;
             $attach = new Attachment;
@@ -719,7 +719,7 @@
             }
         }
 
-        foreach ((array) $object['links'] as $link) {
+        foreach ((array)($object['links'] ?? []) as $link) {
             $attach = new Attachment;
             $attach->setUri($link, 'unknown');
             $vattach->push($attach);
diff --git a/plugins/libkolab/lib/kolab_format_configuration.php b/plugins/libkolab/lib/kolab_format_configuration.php
--- a/plugins/libkolab/lib/kolab_format_configuration.php
+++ b/plugins/libkolab/lib/kolab_format_configuration.php
@@ -80,19 +80,19 @@
         case 'relation':
             $relation = new Relation(strval($object['name']), strval($object['category']));
 
-            if ($object['color']) {
+            if ($object['color'] ?? false) {
                 $relation->setColor($object['color']);
             }
-            if ($object['parent']) {
+            if ($object['parent'] ?? false) {
                 $relation->setParent($object['parent']);
             }
-            if ($object['iconName']) {
+            if ($object['iconName'] ?? false) {
                 $relation->setIconName($object['iconName']);
             }
-            if ($object['priority'] > 0) {
+            if (($object['priority'] ?? 0) > 0) {
                 $relation->setPriority((int) $object['priority']);
             }
-            if (!empty($object['members'])) {
+            if (!empty($object['members'] ?? null)) {
                 $relation->setMembers(self::array2vector($object['members']));
             }
 
@@ -103,10 +103,10 @@
             $collection = new SnippetCollection($object['name']);
             $snippets   = new vectorsnippets;
 
-            foreach ((array) $object['snippets'] as $item) {
+            foreach ((array)($object['snippets'] ?? []) as $item) {
                 $snippet = new snippet($item['name'], $item['text']);
                 $snippet->setTextType(strtolower($item['type']) == 'html' ? Snippet::HTML : Snippet::Plain);
-                if ($item['shortcut']) {
+                if ($item['shortcut'] ?? false) {
                     $snippet->setShortCut($item['shortcut']);
                 }
 
diff --git a/plugins/libkolab/lib/kolab_format_contact.php b/plugins/libkolab/lib/kolab_format_contact.php
--- a/plugins/libkolab/lib/kolab_format_contact.php
+++ b/plugins/libkolab/lib/kolab_format_contact.php
@@ -96,14 +96,14 @@
 
         // do the hard work of setting object values
         $nc = new NameComponents;
-        $nc->setSurnames(self::array2vector($object['surname']));
-        $nc->setGiven(self::array2vector($object['firstname']));
-        $nc->setAdditional(self::array2vector($object['middlename']));
-        $nc->setPrefixes(self::array2vector($object['prefix']));
-        $nc->setSuffixes(self::array2vector($object['suffix']));
+        $nc->setSurnames(self::array2vector($object['surname'] ?? null));
+        $nc->setGiven(self::array2vector($object['firstname'] ?? null));
+        $nc->setAdditional(self::array2vector($object['middlename'] ?? null));
+        $nc->setPrefixes(self::array2vector($object['prefix'] ?? null));
+        $nc->setSuffixes(self::array2vector($object['suffix'] ?? null));
         $this->obj->setNameComponents($nc);
-        $this->obj->setName($object['name']);
-        $this->obj->setCategories(self::array2vector($object['categories']));
+        $this->obj->setName($object['name'] ?? null);
+        $this->obj->setCategories(self::array2vector($object['categories'] ?? null));
 
         if (isset($object['nickname']))
             $this->obj->setNickNames(self::array2vector($object['nickname']));
@@ -113,16 +113,16 @@
         // organisation related properties (affiliation)
         $org = new Affiliation;
         $offices = new vectoraddress;
-        if ($object['organization'])
+        if ($object['organization'] ?? null)
             $org->setOrganisation($object['organization']);
-        if ($object['department'])
+        if ($object['department'] ?? null)
             $org->setOrganisationalUnits(self::array2vector($object['department']));
-        if ($object['profession'])
+        if ($object['profession'] ?? null)
             $org->setRoles(self::array2vector($object['profession']));
 
         $rels = new vectorrelated;
         foreach (array('manager','assistant') as $field) {
-            if (!empty($object[$field])) {
+            if (!empty($object[$field] ?? null)) {
                 $reltype = $this->relatedmap[$field];
                 foreach ((array)$object[$field] as $value) {
                     $rels->push(new Related(Related::Text, $value, $reltype));
@@ -132,11 +132,11 @@
         $org->setRelateds($rels);
 
         // im, email, url
-        $this->obj->setIMaddresses(self::array2vector($object['im']));
+        $this->obj->setIMaddresses(self::array2vector($object['im'] ?? null));
 
         if (class_exists('vectoremail')) {
             $vemails = new vectoremail;
-            foreach ((array)$object['email'] as $email) {
+            foreach ((array)($object['email'] ?? []) as $email) {
                 $type = $this->emailtypes[$email['type']];
                 $vemails->push(new Email($email['address'], intval($type)));
             }
@@ -147,7 +147,7 @@
         $this->obj->setEmailAddresses($vemails);
 
         $vurls = new vectorurl;
-        foreach ((array)$object['website'] as $url) {
+        foreach ((array)($object['website'] ?? []) as $url) {
             $type = $url['type'] == 'blog' ? Url::Blog : Url::NoType;
             $vurls->push(new Url($url['url'], $type));
         }
@@ -155,25 +155,25 @@
 
         // addresses
         $adrs = new vectoraddress;
-        foreach ((array)$object['address'] as $address) {
+        foreach ((array)($object['address'] ?? [])as $address) {
             $adr = new Address;
             $type = $this->addresstypes[$address['type']];
             if (isset($type))
                 $adr->setTypes($type);
-            else if ($address['type'])
+            else if ($address['type'] ?? null)
                 $adr->setLabel($address['type']);
-            if ($address['street'])
+            if ($address['street'] ?? null)
                 $adr->setStreet($address['street']);
-            if ($address['locality'])
+            if ($address['locality'] ?? null)
                 $adr->setLocality($address['locality']);
-            if ($address['code'])
+            if ($address['code'] ?? null)
                 $adr->setCode($address['code']);
-            if ($address['region'])
+            if ($address['region'] ?? null)
                 $adr->setRegion($address['region']);
-            if ($address['country'])
+            if ($address['country'] ?? null)
                 $adr->setCountry($address['country']);
 
-            if ($address['type'] == 'office')
+            if (($address['type'] ?? null) == 'office')
                 $offices->push($adr);
             else
                 $adrs->push($adr);
@@ -188,11 +188,11 @@
 
         // telephones
         $tels = new vectortelephone;
-        foreach ((array)$object['phone'] as $phone) {
+        foreach ((array)($object['phone'] ?? []) as $phone) {
             $tel = new Telephone;
-            if (isset($this->phonetypes[$phone['type']]))
+            if (isset($this->phonetypes[$phone['type'] ?? null]))
                 $tel->setTypes($this->phonetypes[$phone['type']]);
-            $tel->setNumber($phone['number']);
+            $tel->setNumber($phone['number'] ?? null);
             $tels->push($tel);
         }
         $this->obj->setTelephones($tels);
@@ -210,7 +210,7 @@
         if (isset($object['anniversary']))
             $this->obj->setAnniversary(self::get_datetime($object['anniversary'], false, true));
 
-        if (!empty($object['photo'])) {
+        if (!empty($object['photo'] ?? null)) {
             if ($type = rcube_mime::image_content_type($object['photo']))
                 $this->obj->setPhoto($object['photo'], $type);
         }
@@ -230,7 +230,7 @@
             }
         }
         // add other relateds
-        if (is_array($object['related'])) {
+        if (is_array($object['related'] ?? null)) {
             foreach ($object['related'] as $value) {
                 $rels->push(new Related(Related::Text, $value));
             }
@@ -248,8 +248,8 @@
                 $pkcs7_index = $i;
         }
 
-        $pgpkey   = $object['pgppublickey']   ? new Key($object['pgppublickey'], Key::PGP) : new Key();
-        $pkcs7key = $object['pkcs7publickey'] ? new Key($object['pkcs7publickey'], Key::PKCS7_MIME) : new Key();
+        $pgpkey   = ($object['pgppublickey'] ?? false)   ? new Key($object['pgppublickey'], Key::PGP) : new Key();
+        $pkcs7key = ($object['pkcs7publickey'] ?? false) ? new Key($object['pkcs7publickey'], Key::PKCS7_MIME) : new Key();
 
         if ($pgp_index >= 0)
             $keys->set($pgp_index, $pgpkey);
@@ -397,16 +397,16 @@
     {
         $data = '';
         foreach (self::$fulltext_cols as $colname) {
-            list($col, $field) = explode(':', $colname);
+            list($col, $field) = array_pad(explode(':', $colname), 2, null);
 
             if ($field) {
                 $a = array();
-                foreach ((array)$this->data[$col] as $attr)
+                foreach ((array)($this->data[$col] ?? []) as $attr)
                     $a[] = $attr[$field];
                 $val = join(' ', $a);
             }
             else {
-                $val = is_array($this->data[$col]) ? join(' ', $this->data[$col]) : $this->data[$col];
+                $val = is_array($this->data[$col] ?? null) ? join(' ', $this->data[$col] ?? null) : ($this->data[$col] ?? null);
             }
 
             if (strlen($val))
diff --git a/plugins/libkolab/lib/kolab_format_event.php b/plugins/libkolab/lib/kolab_format_event.php
--- a/plugins/libkolab/lib/kolab_format_event.php
+++ b/plugins/libkolab/lib/kolab_format_event.php
@@ -67,18 +67,18 @@
         $status = kolabformat::StatusUndefined;
         if ($object['free_busy'] == 'tentative')
             $status = kolabformat::StatusTentative;
-        if ($object['cancelled'])
+        if ($object['cancelled'] ?? false)
             $status = kolabformat::StatusCancelled;
         else if ($object['status'] && array_key_exists($object['status'], $this->status_map))
             $status = $this->status_map[$object['status']];
         $this->obj->setStatus($status);
 
         // save (recurrence) exceptions
-        if (is_array($object['recurrence']) && is_array($object['recurrence']['EXCEPTIONS']) && !isset($object['exceptions'])) {
+        if (is_array($object['recurrence'] ?? null) && is_array($object['recurrence']['EXCEPTIONS'] ?? null) && !isset($object['exceptions'])) {
             $object['exceptions'] = $object['recurrence']['EXCEPTIONS'];
         }
 
-        if (is_array($object['exceptions'])) {
+        if (is_array($object['exceptions'] ?? null)) {
             $recurrence_id_format = libkolab::recurrence_id_format($object);
             $vexceptions = new vectorevent;
             foreach ($object['exceptions'] as $i => $exception) {
@@ -107,13 +107,13 @@
             $this->obj->setExceptions($vexceptions);
 
             // link with recurrence.EXCEPTIONS for compatibility
-            if (is_array($object['recurrence'])) {
+            if (is_array($object['recurrence'] ?? null)) {
                 $object['recurrence']['EXCEPTIONS'] = &$object['exceptions'];
             }
         }
 
-        if ($object['recurrence_date'] && $object['recurrence_date'] instanceof DateTimeInterface) {
-            if ($object['recurrence']) {
+        if (($object['recurrence_date'] ?? false) && $object['recurrence_date'] instanceof DateTimeInterface) {
+            if ($object['recurrence'] ?? false) {
                 // unset recurrence_date for master events with rrule
                 $object['recurrence_date'] = null;
             }
@@ -216,7 +216,7 @@
             $object['exceptions'] = $recurrence_exceptions;
 
             // also link with recurrence.EXCEPTIONS for compatibility
-            if (is_array($object['recurrence'])) {
+            if (is_array($object['recurrence'] ?? null)) {
                 $object['recurrence']['EXCEPTIONS'] = &$object['exceptions'];
             }
         }
diff --git a/plugins/libkolab/lib/kolab_format_file.php b/plugins/libkolab/lib/kolab_format_file.php
--- a/plugins/libkolab/lib/kolab_format_file.php
+++ b/plugins/libkolab/lib/kolab_format_file.php
@@ -41,14 +41,14 @@
         // set common object properties
         parent::set($object);
 
-        $this->obj->setCategories(self::array2vector($object['categories']));
+        $this->obj->setCategories(self::array2vector($object['categories'] ?? null));
 
         if (isset($object['notes'])) {
             $this->obj->setNote($object['notes']);
         }
 
         // Add file attachment
-        if (!empty($object['_attachments'])) {
+        if (!empty($object['_attachments'] ?? null)) {
             $cid         = key($object['_attachments']);
             $attach_attr = $object['_attachments'][$cid];
             $attach      = new Attachment;
@@ -126,17 +126,17 @@
     {
         $tags = array();
 
-        foreach ((array)$this->data['categories'] as $cat) {
+        foreach ((array)($this->data['categories'] ?? null) as $cat) {
             $tags[] = rcube_utils::normalize_string($cat);
         }
 
         // Add file mimetype to tags
-        if (!empty($this->data['_attachments'])) {
+        if (!empty($this->data['_attachments'] ?? null)) {
             reset($this->data['_attachments']);
             $key        = key($this->data['_attachments']);
             $attachment = $this->data['_attachments'][$key];
 
-            if ($attachment['mimetype']) {
+            if ($attachment['mimetype'] ?? false) {
                 $tags[] = $attachment['mimetype'];
             }
         }
diff --git a/plugins/libkolab/lib/kolab_format_note.php b/plugins/libkolab/lib/kolab_format_note.php
--- a/plugins/libkolab/lib/kolab_format_note.php
+++ b/plugins/libkolab/lib/kolab_format_note.php
@@ -44,8 +44,8 @@
         parent::set($object);
 
         $this->obj->setSummary($object['title']);
-        $this->obj->setDescription($object['description']);
-        $this->obj->setCategories(self::array2vector($object['categories']));
+        $this->obj->setDescription($object['description'] ?? null);
+        $this->obj->setCategories(self::array2vector($object['categories'] ?? null));
 
         $this->set_attachments($object);
 
@@ -99,12 +99,12 @@
     {
         $tags = array();
 
-        foreach ((array)$this->data['categories'] as $cat) {
+        foreach ((array)($this->data['categories'] ?? null) as $cat) {
             $tags[] = rcube_utils::normalize_string($cat);
         }
 
         // add tag for message references
-        foreach ((array)$this->data['links'] as $link) {
+        foreach ((array)($this->data['links'] ?? []) as $link) {
             $url = parse_url($link);
             if ($url['scheme'] == 'imap') {
                 parse_str($url['query'], $param);
@@ -126,11 +126,11 @@
         foreach (self::$fulltext_cols as $col) {
             // convert HTML content to plain text
             if ($col == 'description' && preg_match('/<(html|body)(\s[a-z]|>)/', $this->data[$col], $m) && strpos($this->data[$col], '</'.$m[1].'>')) {
-                $converter = new rcube_html2text($this->data[$col], false, false, 0);
+                $converter = new rcube_html2text($this->data[$col] ?? null, false, false, 0);
                 $val = $converter->get_text();
             }
             else {
-                $val = is_array($this->data[$col]) ? join(' ', $this->data[$col]) : $this->data[$col];
+                $val = is_array($this->data[$col] ?? null) ? join(' ', $this->data[$col] ?? null) : ($this->data[$col] ?? null);
             }
 
             if (strlen($val))
diff --git a/plugins/libkolab/lib/kolab_format_task.php b/plugins/libkolab/lib/kolab_format_task.php
--- a/plugins/libkolab/lib/kolab_format_task.php
+++ b/plugins/libkolab/lib/kolab_format_task.php
@@ -62,8 +62,8 @@
             $status = $this->status_map[$object['status']];
         $this->obj->setStatus($status);
 
-        $this->obj->setStart(self::get_datetime($object['start'], null, $object['start']->_dateonly));
-        $this->obj->setDue(self::get_datetime($object['due'], null, $object['due']->_dateonly));
+        $this->obj->setStart(self::get_datetime($object['start'] ?? null, null, ($object['start'] ?? null) ? $object['start']->_dateonly : null));
+        $this->obj->setDue(self::get_datetime($object['due'] ?? null, null, ($object['due'] ?? null) ? $object['due']->_dateonly : null));
 
         $related = new vectors;
         if (!empty($object['parent_id']))
@@ -140,13 +140,13 @@
         $tags = parent::get_tags($obj);
         $object = $obj ?: $this->data;
 
-        if ($object['status'] == 'COMPLETED' || ($object['complete'] == 100 && empty($object['status'])))
+        if (($object['status'] ?? null) == 'COMPLETED' || (($object['complete'] ?? null) == 100 && empty($object['status'] ?? null)))
             $tags[] = 'x-complete';
 
-        if ($object['priority'] == 1)
+        if (($object['priority'] ?? 0) == 1)
             $tags[] = 'x-flagged';
 
-        if ($object['parent_id'])
+        if ($object['parent_id'] ?? false)
             $tags[] = 'x-parent:' . $object['parent_id'];
 
         return array_unique($tags);
diff --git a/plugins/libkolab/lib/kolab_format_xcal.php b/plugins/libkolab/lib/kolab_format_xcal.php
--- a/plugins/libkolab/lib/kolab_format_xcal.php
+++ b/plugins/libkolab/lib/kolab_format_xcal.php
@@ -117,7 +117,7 @@
             'location'    => $this->obj->location(),
             'description' => $this->obj->description(),
             'url'         => $this->obj->url(),
-            'status'      => $status_map[$this->obj->status()],
+            'status'      => $status_map[$this->obj->status()] ?? null,
             'priority'    => $this->obj->priority(),
             'categories'  => self::vector2array($this->obj->categories()),
             'start'       => self::php_datetime($this->obj->start()),
@@ -345,19 +345,19 @@
         }
 
         $this->obj->setSummary($object['title']);
-        $this->obj->setLocation($object['location']);
+        $this->obj->setLocation($object['location'] ?? null);
         $this->obj->setDescription($object['description']);
         $this->obj->setPriority($object['priority']);
-        $this->obj->setCategories(self::array2vector($object['categories']));
-        $this->obj->setUrl(strval($object['url']));
+        $this->obj->setCategories(self::array2vector($object['categories'] ?? null));
+        $this->obj->setUrl(strval($object['url'] ?? null));
 
         if (method_exists($this->obj, 'setComment')) {
-            $this->obj->setComment($object['comment']);
+            $this->obj->setComment($object['comment'] ?? null);
         }
 
         // process event attendees
         $attendees = new vectorattendee;
-        foreach ((array)$object['attendees'] as $i => $attendee) {
+        foreach ((array)($object['attendees'] ?? []) as $i => $attendee) {
             if ($attendee['role'] == 'ORGANIZER') {
                 $object['organizer'] = $attendee;
             }
@@ -412,7 +412,7 @@
             $this->obj->setOrganizer($organizer);
         }
 
-        if ($object['start'] instanceof DateTimeInterface) {
+        if (($object['start'] ?? null) instanceof DateTimeInterface) {
             $start_tz = $object['start']->getTimezone();
         }
 
@@ -420,7 +420,7 @@
         $rr = new RecurrenceRule;
         $rr->setFrequency(RecurrenceRule::FreqNone);
 
-        if ($object['recurrence'] && !empty($object['recurrence']['FREQ'])) {
+        if (($object['recurrence'] ?? null) && !empty($object['recurrence']['FREQ'])) {
             $freq     = $object['recurrence']['FREQ'];
             $bysetpos = explode(',', $object['recurrence']['BYSETPOS']);
 
@@ -502,7 +502,7 @@
         // save alarm(s)
         $valarms = new vectoralarm;
         $valarm_hashes = array();
-        if ($object['valarms']) {
+        if ($object['valarms'] ?? null) {
             foreach ($object['valarms'] as $valarm) {
                 if (!array_key_exists($valarm['action'], $this->alarm_type_map)) {
                     continue;  // skip unknown alarm types
@@ -577,7 +577,7 @@
             }
         }
         // legacy support
-        else if ($object['alarms']) {
+        else if ($object['alarms'] ?? null) {
             list($offset, $type) = explode(":", $object['alarms']);
 
             if ($type == 'EMAIL' && !empty($object['_owner'])) {  // email alarms implicitly go to event owner
@@ -636,16 +636,16 @@
         $object = $obj ?: $this->data;
 
         foreach (self::$fulltext_cols as $colname) {
-            list($col, $field) = explode(':', $colname);
+            list($col, $field) = array_pad(explode(':', $colname), 2, null);
 
             if ($field) {
                 $a = array();
-                foreach ((array)$object[$col] as $attr)
+                foreach ((array)($object[$col] ?? []) as $attr)
                     $a[] = $attr[$field];
                 $val = join(' ', $a);
             }
             else {
-                $val = is_array($object[$col]) ? join(' ', $object[$col]) : $object[$col];
+                $val = is_array($object[$col] ?? null) ? join(' ', $object[$col]) : $object[$col] ?? null;
             }
 
             if (strlen($val))
@@ -655,7 +655,7 @@
         $words = rcube_utils::normalize_string($data, true);
 
         // collect words from recurrence exceptions
-        if (is_array($object['exceptions'])) {
+        if (is_array($object['exceptions'] ?? null)) {
             foreach ($object['exceptions'] as $exception) {
                 $words = array_merge($words, $this->get_words($exception));
             }
@@ -674,12 +674,12 @@
         $tags = array();
         $object = $obj ?: $this->data;
 
-        if (!empty($object['valarms'])) {
+        if (!empty($object['valarms'] ?? null)) {
             $tags[] = 'x-has-alarms';
         }
 
         // create tags reflecting participant status
-        if (is_array($object['attendees'])) {
+        if (is_array($object['attendees'] ?? null)) {
             foreach ($object['attendees'] as $attendee) {
                 if (!empty($attendee['email']) && !empty($attendee['status']))
                     $tags[] = 'x-partstat:' . $attendee['email'] . ':' . strtolower($attendee['status']);
@@ -687,7 +687,7 @@
         }
 
         // collect tags from recurrence exceptions
-        if (is_array($object['exceptions'])) {
+        if (is_array($object['exceptions'] ?? null)) {
             foreach ($object['exceptions'] as $exception) {
                 $tags = array_merge($tags, $this->get_tags($exception));
             }
@@ -717,10 +717,10 @@
         }
 
         foreach ($this->_scheduling_properties ?: self::$scheduling_properties as $prop) {
-            $a = $old[$prop];
-            $b = $object[$prop];
+            $a = $old[$prop] ?? null;
+            $b = $object[$prop] ?? null;
 
-            if ($object['allday']
+            if (($object['allday'] ?? false)
                 && ($prop == 'start' || $prop == 'end')
                 && $a instanceof DateTimeInterface
                 && $b instanceof DateTimeInterface
diff --git a/plugins/libkolab/lib/kolab_ldap.php b/plugins/libkolab/lib/kolab_ldap.php
--- a/plugins/libkolab/lib/kolab_ldap.php
+++ b/plugins/libkolab/lib/kolab_ldap.php
@@ -70,8 +70,8 @@
                 continue;
             }
 
-            $bind_pass      = $this->config['bind_pass'];
-            $bind_user      = $this->config['bind_user'];
+            $bind_pass      = $this->config['bind_pass'] ?? null;
+            $bind_user      = $this->config['bind_user'] ?? null;
             $bind_dn        = $this->config['bind_dn'];
             $base_dn        = $this->config['base_dn'];
             $groups_base_dn = $this->config['groups']['base_dn'] ?: $base_dn;
@@ -85,12 +85,13 @@
                     $bind_pass = $rcube->get_user_password();
                 }
 
+                $u = null;
                 // Get the pieces needed for variable replacement.
-                if ($fu = ($rcube->get_user_email() ?: $this->config['username'])) {
+                if ($fu = ($rcube->get_user_email() ?: ($this->config['username'] ?? null))) {
                     list($u, $d) = explode('@', $fu);
                 }
                 else {
-                    $d = $this->config['mail_domain'];
+                    $d = $this->config['mail_domain'] ?? null;
                 }
 
                 $dc = 'dc=' . strtr($d, array('.' => ',dc=')); // hierarchal domain string
@@ -513,6 +514,7 @@
             $user = $_SESSION['username'];
         }
 
+        $dc = null;
         if (isset($this->icache[$user])) {
             list($user, $dc) = $this->icache[$user];
         }
diff --git a/plugins/libkolab/lib/kolab_storage.php b/plugins/libkolab/lib/kolab_storage.php
--- a/plugins/libkolab/lib/kolab_storage.php
+++ b/plugins/libkolab/lib/kolab_storage.php
@@ -129,7 +129,7 @@
             $config = self::$config->get($name);
         }
 
-        if (self::$ldap[$name]) {
+        if (self::$ldap[$name] ?? false) {
             return self::$ldap[$name];
         }
 
diff --git a/plugins/libkolab/lib/kolab_storage_cache.php b/plugins/libkolab/lib/kolab_storage_cache.php
--- a/plugins/libkolab/lib/kolab_storage_cache.php
+++ b/plugins/libkolab/lib/kolab_storage_cache.php
@@ -50,6 +50,7 @@
     protected $error = 0;
     protected $server_timezone;
     protected $sync_start;
+    protected $cache_bypassed = 0;
 
 
     /**
@@ -380,7 +381,7 @@
         $mbox_data = $this->imap->folder_data($this->folder->name);
 
         // Removed vanished messages from the database
-        $vanished = (array) rcube_imap_generic::uncompressMessageSet($mbox_data['VANISHED']);
+        $vanished = (array) rcube_imap_generic::uncompressMessageSet($mbox_data['VANISHED'] ?? null);
 
         // Remove redundant entries from IMAP and DB
         $vanished = array_merge($removed, array_intersect($vanished, $existing));
@@ -412,7 +413,7 @@
                 // Deduplication: remove older objects with the same UID
                 // Here we do not resolve conflicts, we just make sure
                 // the most recent version of the object will be used
-                if ($old_msguid = $old_index[$object['uid']]) {
+                if ($old_msguid = ($old_index[$object['uid']] ?? null)) {
                     if ($old_msguid < $msguid) {
                         $del_index[] = $old_msguid;
                     }
@@ -1078,11 +1079,11 @@
      */
     protected function _unserialize($sql_arr)
     {
-        if ($sql_arr['fast-mode'] && !empty($sql_arr['data']) && ($object = json_decode($sql_arr['data'], true))) {
+        if (($sql_arr['fast-mode'] ?? false) && !empty($sql_arr['data']) && ($object = json_decode($sql_arr['data'], true))) {
             $object['uid'] = $sql_arr['uid'];
 
             foreach ($this->data_props as $prop) {
-                if (isset($object[$prop]) && is_array($object[$prop]) && $object[$prop]['cl'] == 'DateTime') {
+                if (isset($object[$prop]) && is_array($object[$prop]) && isset($object[$prop]['cl']) && $object[$prop]['cl'] == 'DateTime') {
                     $object[$prop] = new DateTime($object[$prop]['dt'], new DateTimeZone($object[$prop]['tz']));
                 }
                 else if (!isset($object[$prop]) && isset($sql_arr[$prop])) {
@@ -1098,7 +1099,7 @@
                 $object['changed'] = new DateTime($sql_arr['changed']);
             }
 
-            $object['_type']     = $sql_arr['type'] ?: $this->folder->type;
+            $object['_type']     = $sql_arr['type'] ?? $this->folder->type;
             $object['_msguid']   = $sql_arr['msguid'];
             $object['_mailbox']  = $this->folder->name;
         }
diff --git a/plugins/libkolab/lib/kolab_storage_cache_contact.php b/plugins/libkolab/lib/kolab_storage_cache_contact.php
--- a/plugins/libkolab/lib/kolab_storage_cache_contact.php
+++ b/plugins/libkolab/lib/kolab_storage_cache_contact.php
@@ -38,21 +38,21 @@
         $sql_data['type'] = $object['_type'];
 
         // columns for sorting
-        $sql_data['name']      = rcube_charset::clean($object['name'] . $object['prefix']);
-        $sql_data['firstname'] = rcube_charset::clean($object['firstname'] . $object['middlename'] . $object['surname']);
-        $sql_data['surname']   = rcube_charset::clean($object['surname']   . $object['firstname']  . $object['middlename']);
-        $sql_data['email']     = rcube_charset::clean(is_array($object['email']) ? $object['email'][0] : $object['email']);
+        $sql_data['name']      = rcube_charset::clean(($object['name'] ?? null) . ($object['prefix'] ?? null));
+        $sql_data['firstname'] = rcube_charset::clean(($object['firstname'] ?? null) . ($object['middlename'] ?? null) . ($object['surname'] ?? null));
+        $sql_data['surname']   = rcube_charset::clean(($object['surname'] ?? null)   . ($object['firstname'] ?? null)  . ($object['middlename'] ?? null));
+        $sql_data['email']     = rcube_charset::clean(is_array($object['email'] ?? null) ? $object['email'][0] : ($object['email'] ?? null));
 
-        if (is_array($sql_data['email'])) {
+        if (is_array($sql_data['email'] ?? null)) {
             $sql_data['email'] = $sql_data['email']['address'];
         }
         // avoid value being null
-        if (empty($sql_data['email'])) {
+        if (empty($sql_data['email'] ?? null)) {
             $sql_data['email'] = '';
         }
 
         // use organization if name is empty
-        if (empty($sql_data['name']) && !empty($object['organization'])) {
+        if (empty($sql_data['name'] ?? null) && !empty($object['organization'] ?? null)) {
             $sql_data['name'] = rcube_charset::clean($object['organization']);
         }
 
diff --git a/plugins/libkolab/lib/kolab_storage_cache_event.php b/plugins/libkolab/lib/kolab_storage_cache_event.php
--- a/plugins/libkolab/lib/kolab_storage_cache_event.php
+++ b/plugins/libkolab/lib/kolab_storage_cache_event.php
@@ -35,26 +35,26 @@
     {
         $sql_data = parent::_serialize($object);
 
-        $sql_data['dtstart'] = $this->_convert_datetime($object['start']);
-        $sql_data['dtend']   = $this->_convert_datetime($object['end']);
+        $sql_data['dtstart'] = $this->_convert_datetime($object['start'] ?? null);
+        $sql_data['dtend']   = $this->_convert_datetime($object['end'] ?? null);
 
         // extend date range for recurring events
-        if ($object['recurrence']) {
+        if ($object['recurrence'] ?? null) {
             $recurrence = new kolab_date_recurrence($object['_formatobj']);
             $dtend = $recurrence->end() ?: new DateTime('now +100 years');
             $sql_data['dtend'] = $this->_convert_datetime($dtend);
         }
 
         // extend start/end dates to spawn all exceptions
-        if (is_array($object['exceptions'])) {
+        if (is_array($object['exceptions'] ?? null)) {
             foreach ($object['exceptions'] as $exception) {
-                if ($exception['start'] instanceof DateTimeInterface) {
+                if (($exception['start'] ?? null) instanceof DateTimeInterface) {
                     $exstart = $this->_convert_datetime($exception['start']);
                     if ($exstart < $sql_data['dtstart']) {
                         $sql_data['dtstart'] = $exstart;
                     }
                 }
-                if ($exception['end'] instanceof DateTimeInterface) {
+                if (($exception['end'] ?? null) instanceof DateTimeInterface) {
                     $exend = $this->_convert_datetime($exception['end']);
                     if ($exend > $sql_data['dtend']) {
                         $sql_data['dtend'] = $exend;
diff --git a/plugins/libkolab/lib/kolab_storage_cache_task.php b/plugins/libkolab/lib/kolab_storage_cache_task.php
--- a/plugins/libkolab/lib/kolab_storage_cache_task.php
+++ b/plugins/libkolab/lib/kolab_storage_cache_task.php
@@ -35,8 +35,8 @@
     {
         $sql_data = parent::_serialize($object);
 
-        $sql_data['dtstart'] = $this->_convert_datetime($object['start']);
-        $sql_data['dtend']   = $this->_convert_datetime($object['due']);
+        $sql_data['dtstart'] = $this->_convert_datetime($object['start'] ?? null);
+        $sql_data['dtend']   = $this->_convert_datetime($object['due'] ?? null);
 
         return $sql_data;
     }
diff --git a/plugins/libkolab/lib/kolab_storage_config.php b/plugins/libkolab/lib/kolab_storage_config.php
--- a/plugins/libkolab/lib/kolab_storage_config.php
+++ b/plugins/libkolab/lib/kolab_storage_config.php
@@ -186,10 +186,10 @@
             $object['type'] = $type;
         }
 
-        $status = $folder->save($object, self::FOLDER_TYPE . '.' . $object['type'], $object['uid']);
+        $status = $folder->save($object, self::FOLDER_TYPE . '.' . ($object['type'] ?? null), $object['uid'] ?? null);
 
         // on success, update cached tags list
-        if ($status && $object['category'] == 'tag' && is_array($this->tags)) {
+        if ($status && ($object['category'] ?? null) == 'tag' && is_array($this->tags)) {
             $found = false;
             unset($object['_formatobj']); // we don't need it anymore
 
@@ -256,7 +256,7 @@
         }
 
         // find folder object
-        if ($object['_mailbox']) {
+        if ($object['_mailbox'] ?? false) {
             foreach ($this->folders as $folder) {
                 if ($folder->name == $object['_mailbox']) {
                     break;
@@ -676,7 +676,7 @@
 
             // assign links to objects
             foreach ((array) $relation['members'] as $member) {
-                if (($id = $ids[$member]) !== null) {
+                if (($id = ($ids[$member] ?? null)) !== null) {
                     foreach ($id as $i) {
                         $records[$i]['links'] = array_unique(array_merge($records[$i]['links'], $members));
                     }
diff --git a/plugins/libkolab/lib/kolab_storage_dataset.php b/plugins/libkolab/lib/kolab_storage_dataset.php
--- a/plugins/libkolab/lib/kolab_storage_dataset.php
+++ b/plugins/libkolab/lib/kolab_storage_dataset.php
@@ -155,7 +155,7 @@
             return $this->data[$offset];
         }
 
-        if ($uid = $this->index[$offset]) {
+        if ($uid = ($this->index[$offset] ?? null)) {
             return $this->cache->get($uid);
         }
 
diff --git a/plugins/libkolab/lib/kolab_storage_folder.php b/plugins/libkolab/lib/kolab_storage_folder.php
--- a/plugins/libkolab/lib/kolab_storage_folder.php
+++ b/plugins/libkolab/lib/kolab_storage_folder.php
@@ -158,7 +158,7 @@
 
         if ($metadata !== null) {
             foreach ($metakeys as $key) {
-                if ($uid = $metadata[$key]) {
+                if ($uid = ($metadata[$key] ?? null)) {
                     return $uid;
                 }
             }
@@ -197,7 +197,7 @@
     {
         $fdata = $this->get_imap_data();
         $this->check_error();
-        return sprintf('%d-%d-%d', $fdata['UIDVALIDITY'], $fdata['HIGHESTMODSEQ'], $fdata['UIDNEXT']);
+        return sprintf('%d-%d-%d', $fdata['UIDVALIDITY'] ?? null, $fdata['HIGHESTMODSEQ'] ?? null, $fdata['UIDNEXT'] ?? null);
     }
 
     /**
@@ -500,6 +500,7 @@
         $attachments = array();
 
         // get XML part
+        $xml = null;
         foreach ((array)$message->attachments as $part) {
             if (!$xml && ($part->mimetype == $content_type || preg_match('!application/([a-z.]+\+)?xml!i', $part->mimetype))) {
                 $xml = $message->get_part_body($part->mime_id, true);
@@ -607,7 +608,7 @@
             $type = $this->type;
 
         // copy attachments from old message
-        $copyfrom = $object['_copyfrom'] ?: $object['_msguid'];
+        $copyfrom = $object['_copyfrom'] ?? ($object['_msguid'] ?? null);
         if (!empty($copyfrom) && ($old = $this->cache->get($copyfrom, $type, $object['_mailbox']))) {
             foreach ((array)$old['_attachments'] as $key => $att) {
                 if (!isset($object['_attachments'][$key])) {
@@ -636,7 +637,7 @@
         }
 
         // process attachments
-        if (is_array($object['_attachments'])) {
+        if (is_array($object['_attachments'] ?? null)) {
             $numatt = count($object['_attachments']);
             foreach ($object['_attachments'] as $key => $attachment) {
                 // FIXME: kolab_storage and Roundcube attachment hooks use different fields!
@@ -701,7 +702,7 @@
 
             // update cache with new UID
             if ($result) {
-                $old_uid = $object['_msguid'];
+                $old_uid = $object['_msguid'] ?? null;
 
                 $object['_msguid'] = $result;
                 $object['_mailbox'] = $this->name;
@@ -918,10 +919,11 @@
     private function build_message(&$object, $type, $binary, &$body_file)
     {
         // load old object to preserve data we don't understand/process
-        if (is_object($object['_formatobj']))
+        $format = null;
+        if (is_object($object['_formatobj'] ?? null))
             $format = $object['_formatobj'];
-        else if ($object['_msguid'] && ($old = $this->cache->get($object['_msguid'], $type, $object['_mailbox'])))
-            $format = $old['_formatobj'];
+        else if ($object['_msguid'] ?? null && ($old = $this->cache->get($object['_msguid'], $type, $object['_mailbox'] ?? null)))
+            $format = $old['_formatobj'] ?? null;
 
         // create new kolab_format instance
         if (!$format)
@@ -995,8 +997,10 @@
         );
         $part_id++;
 
+        $is_file = false;
+
         // save object attachments as separate parts
-        foreach ((array)$object['_attachments'] as $key => $att) {
+        foreach ((array)($object['_attachments'] ?? []) as $key => $att) {
             if (empty($att['content']) && !empty($att['id'])) {
                 // @TODO: use IMAP CATENATE to skip attachment fetch+push operation
                 $msguid = $object['_copyfrom'] ?: ($object['_msguid'] ?: $object['uid']);
diff --git a/plugins/libkolab/libkolab.php b/plugins/libkolab/libkolab.php
--- a/plugins/libkolab/libkolab.php
+++ b/plugins/libkolab/libkolab.php
@@ -67,7 +67,7 @@
         }
 
         // embed scripts and templates for email message audit trail
-        if ($rcmail->task == 'mail' && self::get_bonnie_api()) {
+        if (property_exists($rcmail, 'task') && $rcmail->task == 'mail' && self::get_bonnie_api()) {
             if ($rcmail->output->type == 'html') {
                 $this->add_hook('render_page', array($this, 'bonnie_render_page'));
                 $this->include_script('libkolab.js');
diff --git a/plugins/tasklist/drivers/kolab/tasklist_kolab_driver.php b/plugins/tasklist/drivers/kolab/tasklist_kolab_driver.php
--- a/plugins/tasklist/drivers/kolab/tasklist_kolab_driver.php
+++ b/plugins/tasklist/drivers/kolab/tasklist_kolab_driver.php
@@ -653,11 +653,11 @@
             }
         }
 
-        if ($filter['since']) {
+        if ($filter['since'] ?? false) {
             $query[] = array('changed', '>=', $filter['since']);
         }
 
-        if ($filter['uid']) {
+        if ($filter['uid'] ?? false) {
             $query[] = array('uid', '=', (array) $filter['uid']);
         }
 
@@ -709,7 +709,7 @@
                 $folder = $this->folders[$list_id];
             if (is_numeric($list_id) || !$folder)
                 continue;
-            if (!$this->tasks[$id] && ($object = $folder->get_object($id))) {
+            if (!($this->tasks[$id] ?? false) && ($object = $folder->get_object($id))) {
                 $this->load_tags($object);
                 $this->tasks[$id] = $this->_to_rcube_task($object, $list_id);
                 break;
@@ -1258,20 +1258,20 @@
         $task = array(
             'id' => $id_prefix . $record['uid'],
             'uid' => $record['uid'],
-            'title' => $record['title'],
+            'title' => $record['title'] ?? null,
 //            'location' => $record['location'],
-            'description' => $record['description'],
-            'flagged' => $record['priority'] == 1,
-            'complete' => floatval($record['complete'] / 100),
-            'status' => $record['status'],
-            'parent_id' => $record['parent_id'] ? $id_prefix . $record['parent_id'] : null,
-            'recurrence' => $record['recurrence'],
-            'attendees' => $record['attendees'],
-            'organizer' => $record['organizer'],
-            'sequence' => $record['sequence'],
-            'tags' => $record['tags'],
+            'description' => $record['description'] ?? null,
+            'flagged' => ($record['priority'] ?? null) == 1,
+            'complete' => floatval(($record['complete'] ?? null) / 100),
+            'status' => $record['status'] ?? null,
+            'parent_id' => ($record['parent_id'] ?? null) ? $id_prefix . $record['parent_id'] : null,
+            'recurrence' => $record['recurrence'] ?? null,
+            'attendees' => $record['attendees'] ?? null,
+            'organizer' => $record['organizer'] ?? null,
+            'sequence' => $record['sequence'] ?? null,
+            'tags' => $record['tags'] ?? null,
             'list' => $list_id,
-            'links' => $record['links'],
+            'links' => $record['links'] ?? null,
         );
 
         // we can sometimes skip this expensive operation
@@ -1280,7 +1280,7 @@
         }
 
         // convert from DateTime to internal date format
-        if ($record['due'] instanceof DateTimeInterface) {
+        if (($record['due'] ?? null) instanceof DateTimeInterface) {
             $due = $this->plugin->lib->adjust_timezone($record['due']);
             $task['date'] = $due->format('Y-m-d');
             if (empty($record['due']->_dateonly)) {
@@ -1288,24 +1288,24 @@
             }
         }
         // convert from DateTime to internal date format
-        if ($record['start'] instanceof DateTimeInterface) {
+        if (($record['start'] ?? null) instanceof DateTimeInterface) {
             $start = $this->plugin->lib->adjust_timezone($record['start']);
             $task['startdate'] = $start->format('Y-m-d');
             if (empty($record['start']->_dateonly)) {
                 $task['starttime'] = $start->format('H:i');
             }
         }
-        if ($record['changed'] instanceof DateTimeInterface) {
+        if (($record['changed'] ?? null) instanceof DateTimeInterface) {
             $task['changed'] = $record['changed'];
         }
-        if ($record['created'] instanceof DateTimeInterface) {
+        if (($record['created'] ?? null) instanceof DateTimeInterface) {
             $task['created'] = $record['created'];
         }
 
-        if ($record['valarms']) {
+        if ($record['valarms'] ?? false) {
             $task['valarms'] = $record['valarms'];
         }
-        else if ($record['alarms']) {
+        else if ($record['alarms'] ?? false) {
             $task['alarms'] = $record['alarms'];
         }
 
@@ -1320,7 +1320,7 @@
             }
         }
 
-        if (!empty($record['_attachments'])) {
+        if (!empty($record['_attachments'] ?? [])) {
             foreach ($record['_attachments'] as $key => $attachment) {
                 if ($attachment !== false) {
                     if (empty($attachment['name'])) {
@@ -1381,10 +1381,10 @@
         if ($task['complete'] == 1.0 && empty($task['complete']))
             $object['status'] = 'COMPLETED';
 
-        if ($task['flagged'])
+        if ($task['flagged'] ?? false)
             $object['priority'] = 1;
         else
-            $object['priority'] = $old['priority'] > 1 ? $old['priority'] : 0;
+            $object['priority'] = ($old['priority'] ?? 0) > 1 ? $old['priority'] : 0;
 
         // remove list: prefix from parent_id
         if (!empty($task['parent_id']) && strpos($task['parent_id'], $id_prefix) === 0) {
@@ -1448,12 +1448,12 @@
         }
 
         // email links and tags are stored separately
-        $links = $task['links'];
-        $tags  = $task['tags'];
+        $links = $task['links'] ?? null;
+        $tags  = $task['tags'] ?? null;
         unset($task['tags'], $task['links']);
 
         // moved from another folder
-        if ($task['_fromlist'] && ($fromfolder = $this->get_folder($task['_fromlist']))) {
+        if (($task['_fromlist'] ?? false) && ($fromfolder = $this->get_folder($task['_fromlist']))) {
             if (!$fromfolder->move($task['uid'], $folder))
                 return false;
 
@@ -1461,7 +1461,8 @@
         }
 
         // load previous version of this task to merge
-        if ($task['id']) {
+        $old = null;
+        if ($task['id'] ?? null) {
             $old = $folder->get_object($task['uid']);
             if (!$old || PEAR::isError($old))
                 return false;
diff --git a/plugins/tasklist/tasklist_ui.php b/plugins/tasklist/tasklist_ui.php
--- a/plugins/tasklist/tasklist_ui.php
+++ b/plugins/tasklist/tasklist_ui.php
@@ -218,7 +218,7 @@
             $prop = $data[$id];
             $is_collapsed = false; // TODO: determine this somehow?
 
-            $content = $this->tasklist_list_item($id, $prop, $jsenv, $attrib['activeonly']);
+            $content = $this->tasklist_list_item($id, $prop, $jsenv, $attrib['activeonly'] ?? null);
 
             if (!empty($folder->children)) {
                 $content .= html::tag('ul', array('style' => ($is_collapsed ? "display:none;" : null)),
@@ -294,7 +294,7 @@
             }
             $actions .= html::a(['href' => '#', 'class' => 'quickview', 'title' => $this->plugin->gettext('focusview'), 'role' => 'checkbox', 'aria-checked' => 'false'], ' ');
             if (isset($prop['subscribed'])) {
-                $action .= html::a(['href' => '#', 'class' => 'subscribed', 'title' => $this->plugin->gettext('tasklistsubscribe'), 'role' => 'checkbox', 'aria-checked' => $prop['subscribed'] ? 'true' : 'false'], ' ');
+                $actions .= html::a(['href' => '#', 'class' => 'subscribed', 'title' => $this->plugin->gettext('tasklistsubscribe'), 'role' => 'checkbox', 'aria-checked' => $prop['subscribed'] ? 'true' : 'false'], ' ');
             }
 
             return html::div(join(' ', $classes),