Changes of Revision 50

kolab-syncroton.spec Changed
x
 
1
@@ -36,7 +36,7 @@
2
 %global _ap_sysconfdir %{_sysconfdir}/%{httpd_name}
3
 
4
 Name:           kolab-syncroton
5
-Version:        2.3.23
6
+Version:        2.4.0
7
 Release:        1%{?dist}
8
 Summary:        ActiveSync for Kolab Groupware
9
 
10
@@ -44,7 +44,7 @@
11
 License:        LGPLv2
12
 URL:            http://www.syncroton.org
13
 
14
-Source0:        https://mirror.kolabenterprise.com/pub/releases/%{name}-%{version}.tar.gz
15
+Source0:        %{name}-%{version}.tar.gz
16
 Source1:        kolab-syncroton.logrotate
17
 Source2:        plesk.kolab_syncroton.inc.php
18
 
19
@@ -68,6 +68,7 @@
20
 %endif
21
 %endif
22
 
23
+Requires:       roundcubemail
24
 Requires:       logrotate
25
 %if 0%{?rhel} < 8
26
 Requires:       php-kolabformat
27
@@ -171,7 +172,7 @@
28
 fi
29
 
30
 /usr/share/roundcubemail/bin/updatedb.sh \
31
-    --dir /usr/share/doc/kolab-syncroton-%{version}/SQL/ \
32
+    --dir /usr/share/doc/kolab-syncroton/SQL/ \
33
     --package syncroton \
34
     >/dev/null 2>&1 || :
35
 
36
@@ -192,6 +193,9 @@
37
 %attr(0770,%{httpd_user},%{httpd_group}) %{_var}/log/%{name}
38
 
39
 %changelog
40
+* Wed May 10 2023 Christian Mollekopf <mollekopf@apheleia-it.ch> - 2.4.0-1
41
+- Release version 2.4.0
42
+
43
 * Fri Feb 04 2022 Jeroen van Meeuwen <vanmeeuwen@apheleia-it.ch> - 2.3.22-1
44
 - Release version 2.3.22
45
 
46
debian.changelog Changed
11
 
1
@@ -1,3 +1,9 @@
2
+kolab-syncroton (2.4.0-0~kolab1) unstable; urgency=low
3
+
4
+  * Release version 2.4.0
5
+
6
+ -- Christian Mollekopf <mollekopf@apheleia-it.ch>  Wed, 10 May 2023 15:13:40 +0200
7
+
8
 kolab-syncroton (2.3.23-0~kolab1) unstable; urgency=low
9
 
10
   * Release version 2.3.23
11
kolab-syncroton-2.4.0.tar.gz/docs/SQL/mysql/2023100500.sql Added
4
 
1
@@ -0,0 +1,2 @@
2
+
3
+ALTER TABLE `syncroton_synckey` ADD `client_id_map` longblob DEFAULT NULL;
4
kolab-syncroton-2.3.23.tar.gz/lib/ext/Syncroton/Command/Settings.php -> kolab-syncroton-2.4.0.tar.gz/lib/ext/Syncroton/Command/Settings.php Changed
9
 
1
@@ -110,6 +110,7 @@
2
 
3
         // Out-of-Office
4
         if (!empty($this->_OofGet)) {
5
+            $OofGet = null;
6
             try {
7
                 $OofGet = $this->_deviceBackend->getOOF($this->_OofGet);
8
             } catch (Exception $e) {
9
kolab-syncroton-2.3.23.tar.gz/lib/ext/Syncroton/Command/Sync.php -> kolab-syncroton-2.4.0.tar.gz/lib/ext/Syncroton/Command/Sync.php Changed
201
 
1
@@ -243,7 +243,12 @@
2
                 continue;
3
             }
4
             
5
-            // check for invalid sycnkey
6
+            $syncKeyReused = $this->_syncStateBackend->haveNext($this->_device, $collectionData->folder, $collectionData->syncKey);
7
+            if ($syncKeyReused) {
8
+                if ($this->_logger instanceof Zend_Log) 
9
+                    $this->_logger->warn(__METHOD__ . '::' . __LINE__ . " already known synckey {$collectionData->syncKey} provided");
10
+            }
11
+            // check for invalid synckey
12
             if(($collectionData->syncState = $this->_syncStateBackend->validate($this->_device, $collectionData->folder, $collectionData->syncKey)) === false) {
13
                 if ($this->_logger instanceof Zend_Log) 
14
                     $this->_logger->warn(__METHOD__ . '::' . __LINE__ . " invalid synckey {$collectionData->syncKey} provided");
15
@@ -301,6 +306,11 @@
16
                 if ($this->_logger instanceof Zend_Log) 
17
                     $this->_logger->info(__METHOD__ . '::' . __LINE__ . " found " . count($adds) . " entries to be added to server");
18
                 
19
+                $clientIdMap = ;
20
+                if ($syncKeyReused && $collectionData->syncState->clientIdMap) {
21
+                    $clientIdMap = Zend_Json::decode($collectionData->syncState->clientIdMap);
22
+                }
23
+
24
                 foreach ($adds as $add) {
25
                     if ($this->_logger instanceof Zend_Log) 
26
                         $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " add entry with clientId " . (string) $add->ClientId);
27
@@ -309,20 +319,35 @@
28
                         if ($this->_logger instanceof Zend_Log) 
29
                             $this->_logger->info(__METHOD__ . '::' . __LINE__ . " adding entry as new");
30
                         
31
-                        $serverId = $dataController->createEntry($collectionData->collectionId, new $dataClass($add->ApplicationData));
32
-                        
33
-                        $clientModifications'added'$serverId = array(
34
-                            'clientId'     => (string)$add->ClientId,
35
-                            'serverId'     => $serverId,
36
-                            'status'       => self::STATUS_SUCCESS,
37
-                            'contentState' => $this->_contentStateBackend->create(new Syncroton_Model_Content(array(
38
-                                'device_id'        => $this->_device,
39
-                                'folder_id'        => $collectionData->folder,
40
-                                'contentid'        => $serverId,
41
-                                'creation_time'    => $this->_syncTimeStamp,
42
-                                'creation_synckey' => $collectionData->syncKey + 1
43
-                            )))
44
-                        );
45
+                        $clientId = (string)$add->ClientId;
46
+                        // If the sync key was reused, but we don't have a $clientId mapping,
47
+                        // this means the client sent a new item with the same sync_key.
48
+                        if ($syncKeyReused && array_key_exists($clientId, $clientIdMap)) {
49
+                            // We don't normally store the clientId, so if a command with Add's is resent,
50
+                            // we have to look-up the corresponding serverId using a cached clientId => serverId mapping,
51
+                            // otherwise we would duplicate all added items on resend.
52
+                            $serverId = $clientIdMap$clientId;
53
+                            $clientModifications'added'$serverId = array(
54
+                                'clientId'     => (string)$add->ClientId,
55
+                                'serverId'     => $serverId,
56
+                                'status'       => self::STATUS_SUCCESS,
57
+                                'contentState' => null
58
+                            );
59
+                        } else {
60
+                            $serverId = $dataController->createEntry($collectionData->collectionId, new $dataClass($add->ApplicationData));
61
+                            $clientModifications'added'$serverId = array(
62
+                                'clientId'     => (string)$add->ClientId,
63
+                                'serverId'     => $serverId,
64
+                                'status'       => self::STATUS_SUCCESS,
65
+                                'contentState' => $this->_contentStateBackend->create(new Syncroton_Model_Content(array(
66
+                                    'device_id'        => $this->_device,
67
+                                    'folder_id'        => $collectionData->folder,
68
+                                    'contentid'        => $serverId,
69
+                                    'creation_time'    => $this->_syncTimeStamp,
70
+                                    'creation_synckey' => $collectionData->syncKey + 1
71
+                                )))
72
+                            );
73
+                        }
74
                         
75
                     } catch (Exception $e) {
76
                         if ($this->_logger instanceof Zend_Log) 
77
@@ -336,7 +361,7 @@
78
             }
79
             
80
             // handle changes, but only if not first sync
81
-            if($collectionData->syncKey > 1 && $collectionData->hasClientChanges()) {
82
+            if(!$syncKeyReused && $collectionData->syncKey > 1 && $collectionData->hasClientChanges()) {
83
                 $changes = $collectionData->getClientChanges();
84
                 
85
                 if ($this->_logger instanceof Zend_Log) 
86
@@ -367,7 +392,7 @@
87
             }
88
             
89
             // handle deletes, but only if not first sync
90
-            if($collectionData->hasClientDeletes()) {
91
+            if(!$syncKeyReused && $collectionData->hasClientDeletes()) {
92
                 $deletes = $collectionData->getClientDeletes();
93
                 if ($this->_logger instanceof Zend_Log) 
94
                     $this->_logger->info(__METHOD__ . '::' . __LINE__ . " found " . count($deletes) . " entries to be deleted on server");
95
@@ -670,8 +695,8 @@
96
                                     if ($this->_logger instanceof Zend_Log)
97
                                         $this->_logger->info(__METHOD__ . '::' . __LINE__ . " skipped added entry: " . $serverId);
98
                                     unset($serverModifications'added'$id);
99
-                                    }
100
                                 }
101
+                            }
102
 
103
                             // entries to be deleted
104
                             $serverModifications'deleted' = array_diff($allClientEntries, $allServerEntries);
105
@@ -731,7 +756,7 @@
106
                     foreach($clientModifications'added' as $entryData) {
107
                         $add = $responses->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'Add'));
108
                         $add->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'ClientId', $entryData'clientId'));
109
-                        // we have no serverId is the add failed
110
+                        // we have no serverId if the add failed
111
                         if(isset($entryData'serverId')) {
112
                             $add->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'ServerId', $entryData'serverId'));
113
                         }
114
@@ -990,50 +1015,65 @@
115
                     $collectionData->syncState->pendingdata = null;
116
                 }
117
                 
118
-                
119
-                if (!empty($clientModifications'added')) {
120
-                    if ($this->_logger instanceof Zend_Log) 
121
-                        $this->_logger->info(__METHOD__ . '::' . __LINE__ . " remove previous synckey as client added new entries");
122
-                    $keepPreviousSyncKey = false;
123
-                } else {
124
-                    $keepPreviousSyncKey = true;
125
-                }
126
-                
127
                 $collectionData->syncState->lastsync = clone $this->_syncTimeStamp;
128
                 // increment sync timestamp by 1 second
129
                 $collectionData->syncState->lastsync->modify('+1 sec');
130
-                
131
-                try {
132
-                    $transactionId = Syncroton_Registry::getTransactionManager()->startTransaction(Syncroton_Registry::getDatabase());
133
-                    
134
-                    // store new synckey
135
-                    $this->_syncStateBackend->create($collectionData->syncState, $keepPreviousSyncKey);
136
-                    
137
-                    // store contentstates for new entries added to client
138
-                    foreach($newContentStates as $state) {
139
-                        $this->_contentStateBackend->create($state);
140
-                    }
141
-                    
142
-                    // remove contentstates for entries to be deleted on client
143
-                    foreach($deletedContentStates as $state) {
144
-                        $this->_contentStateBackend->delete($state);
145
+                if (!empty($clientModifications'added')) {
146
+                    // Store a client id mapping in case we encounter a reused sync_key in a future request.
147
+                    $newClientIdMap = ;
148
+                    foreach($clientModifications'added' as $entryData) {
149
+                        $newClientIdMap$entryData'clientId' = $entryData'serverId';
150
                     }
151
-                    
152
-                    Syncroton_Registry::getTransactionManager()->commitTransaction($transactionId);
153
-                } catch (Zend_Db_Statement_Exception $zdse) {
154
-                    // something went wrong
155
-                    // maybe another parallel request added a new synckey
156
-                    // we must remove data added from client
157
-                    if (!empty($clientModifications'added')) {
158
-                        foreach ($clientModifications'added' as $added) {
159
-                            $this->_contentStateBackend->delete($added'contentState');
160
-                            $dataController->deleteEntry($collectionData->collectionId, $added'serverId', array());
161
+                    $collectionData->syncState->clientIdMap = Zend_Json::encode($newClientIdMap);
162
+                }
163
+                
164
+                //Retry in case of deadlock
165
+                $retries = 0;
166
+                while (True) {
167
+                    try {
168
+                        $transactionId = Syncroton_Registry::getTransactionManager()->startTransaction(Syncroton_Registry::getDatabase());
169
+                        // store new synckey
170
+                        $this->_syncStateBackend->create($collectionData->syncState, true);
171
+                        
172
+                        // store contentstates for new entries added to client
173
+                        foreach($newContentStates as $state) {
174
+                            $this->_contentStateBackend->create($state);
175
+                        }
176
+                        
177
+                        // remove contentstates for entries to be deleted on client
178
+                        foreach($deletedContentStates as $state) {
179
+                            $this->_contentStateBackend->delete($state);
180
+                        }
181
+
182
+                        Syncroton_Registry::getTransactionManager()->commitTransaction($transactionId);
183
+                        break;
184
+                    } catch (Exception $zdse) {
185
+                        $retries++;
186
+                        if ($retries > 5) {
187
+                            if ($this->_logger instanceof Zend_Log) 
188
+                                $this->_logger->warn(__METHOD__ . '::' . __LINE__ . ' exception while storing new synckey. Aborting after 5 retries.');
189
+
190
+                            // something went wrong
191
+                            // maybe another parallel request added a new synckey
192
+                            // we must remove data added from client
193
+                            if (!empty($clientModifications'added')) {
194
+                                foreach ($clientModifications'added' as $added) {
195
+                                    $this->_contentStateBackend->delete($added'contentState');
196
+                                    $dataController->deleteEntry($collectionData->collectionId, $added'serverId', array());
197
+                                }
198
+                            }
199
+                            
200
+                            Syncroton_Registry::getTransactionManager()->rollBack();
201
kolab-syncroton-2.3.23.tar.gz/lib/ext/Syncroton/Exception/Status/Settings.php -> kolab-syncroton-2.4.0.tar.gz/lib/ext/Syncroton/Exception/Status/Settings.php Changed
19
 
1
@@ -32,11 +32,11 @@
2
      * @var array
3
      */
4
     protected $_errorMessages = array(
5
-        self::PROTOCOL_ERROR        => "Protocol error";
6
-        self::ACCESS_DENIED         => "Access denied";
7
-        self::SERVICE_UNAVAILABLE   => "Server unavailable";
8
-        self::INVALID_ARGUMENTS     => "Invalid arguments";
9
-        self::CONFLICTING_ARGUMENTS => "Conflicting arguments";
10
-        self::DENIED_BY_POLICY      => "Denied by policy. Disabled by administrator";
11
+        self::PROTOCOL_ERROR        => "Protocol error",
12
+        self::ACCESS_DENIED         => "Access denied",
13
+        self::SERVICE_UNAVAILABLE   => "Server unavailable",
14
+        self::INVALID_ARGUMENTS     => "Invalid arguments",
15
+        self::CONFLICTING_ARGUMENTS => "Conflicting arguments",
16
+        self::DENIED_BY_POLICY      => "Denied by policy. Disabled by administrator",
17
     );
18
 }
19
kolab-syncroton-2.3.23.tar.gz/lib/ext/Syncroton/Model/ISyncState.php -> kolab-syncroton-2.4.0.tar.gz/lib/ext/Syncroton/Model/ISyncState.php Changed
9
 
1
@@ -19,6 +19,7 @@
2
  * @property    string    counter
3
  * @property    DateTime  lastsync
4
  * @property    string    pendingdata
5
+ * @property    string    client_id_map
6
  */
7
 interface Syncroton_Model_ISyncState
8
 {
9
kolab-syncroton-2.3.23.tar.gz/lib/ext/Syncroton/Wbxml/Encoder.php -> kolab-syncroton-2.4.0.tar.gz/lib/ext/Syncroton/Wbxml/Encoder.php Changed
201
 
1
@@ -20,27 +20,6 @@
2
 class Syncroton_Wbxml_Encoder extends Syncroton_Wbxml_Abstract
3
 {
4
     /**
5
-     * stack of dtd objects
6
-     *
7
-     * @var array
8
-     */
9
-    protected $_dtdStack = array();
10
-    
11
-    /**
12
-     * stack of stream resources
13
-     *
14
-     * @var array
15
-     */
16
-    protected $_streamStack = array();
17
-    
18
-    /**
19
-     * stack of levels when to pop data from the other stacks
20
-     *
21
-     * @var array
22
-     */
23
-    protected $_popStack = array();
24
-        
25
-    /**
26
      * count level of tags
27
      *
28
      * @var string
29
@@ -48,27 +27,6 @@
30
     protected $_level = 0;
31
     
32
     /**
33
-     * when to take data next time from the different stacks
34
-     *
35
-     * @var unknown_type
36
-     */
37
-    protected $_nextStackPop = NULL;
38
-    
39
-    /**
40
-     * collect data trough different calls to _handleCharacters
41
-     *
42
-     * @var string
43
-     */
44
-    protected $_currentTagData = NULL;
45
-    
46
-    /**
47
-     * the current tag as read by the parser
48
-     *
49
-     * @var string
50
-     */
51
-    protected $_currentTag = NULL;
52
-    
53
-    /**
54
      * the constructor
55
      *
56
      * @param resource $_stream
57
@@ -151,67 +109,66 @@
58
     {
59
         $_dom->formatOutput = false;
60
         
61
-        $tempStream = tmpfile();
62
-
63
-        $meta_data = stream_get_meta_data($tempStream);
64
-        $filename = $meta_data"uri";
65
-        $_dom->save($filename);
66
-        rewind($tempStream);
67
-        
68
         $this->_initialize($_dom);
69
-        
70
-        $parser = xml_parser_create_ns($this->_charSet, ';');
71
-        xml_set_object($parser, $this);
72
-        xml_set_element_handler($parser, '_handleStartTag', '_handleEndTag');
73
-        xml_set_character_data_handler($parser, '_handleCharacters');
74
-        xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
75
-        
76
-        while (!feof($tempStream)) {
77
-            if (!xml_parse($parser, fread($tempStream, 1048576), feof($tempStream))) {
78
-                // uncomment to write xml document to file
79
-                #rewind($tempStream);
80
-                #$xmlStream = fopen(tempnam(sys_get_temp_dir(), "xmlerrors"), 'r+');
81
-                #stream_copy_to_stream($tempStream, $xmlStream);
82
-                #fclose($xmlStream);
83
-                
84
-                throw new Syncroton_Wbxml_Exception(sprintf('XML error: %s at line %d',
85
-                    xml_error_string(xml_get_error_code($parser)),
86
-                    xml_get_current_line_number($parser)
87
-                ));
88
+        $this->_traverseDom($_dom);
89
+    }
90
+
91
+    private function getAttributes($node)
92
+    {
93
+        $attributes = array();
94
+        if ($node->attributes) {
95
+            for ($i = 0; $i < $node->attributes->length; ++$i) {
96
+                $attributes$node->attributes->item($i)->name = $node->attributes->item($i)->value;
97
             }
98
         }
99
+        return $attributes;
100
+    }
101
 
102
-        fclose($tempStream);
103
-        xml_parser_free($parser);
104
+    private function writeNode($node, $withContent = false, $data = null) {
105
+        if($this->_codePage->getNameSpace() != $node->namespaceURI) {
106
+            $this->_switchCodePage($node->namespaceURI);
107
+        }
108
+        $this->_writeTag($node->localName, $this->getAttributes($node), $withContent, $data);
109
     }
110
 
111
-    /**
112
-     * get's called by xml parser when tag starts
113
-     *
114
-     * @param resource $_parser
115
-     * @param string $_tag current tag prefixed with namespace
116
-     * @param array $_attributes list of tag attributes
117
-     */
118
-    protected function _handleStartTag($_parser, $_tag, $_attributes)
119
+    protected function _traverseDom($_dom)
120
     {
121
-        $this->_level++;
122
-        $this->_currentTagData = null;
123
-        
124
-        // write data for previous tag happens whith <tag1><tag2>
125
-        if($this->_currentTag !== NULL) {
126
-            $this->_writeTag($this->_currentTag, $this->_attributes, true);
127
+        if ($_dom->childNodes->length == 0) {
128
+            return false;
129
         }
130
-
131
-        list($nameSpace, $this->_currentTag) = explode(';', $_tag);
132
-
133
-        if($this->_codePage->getNameSpace() != $nameSpace) {
134
-            $this->_switchCodePage($nameSpace);
135
+        // print(str_pad("", $this->_level, " ") . "traversing {$_dom->nodeName}" . "\n");
136
+        $this->_level++;
137
+        $prevNode = $_dom;
138
+        $foundElementNode = false;
139
+        foreach ($_dom->childNodes as $node) {
140
+            if ($node->nodeType == XML_ELEMENT_NODE) {
141
+                $foundElementNode = true;
142
+                if ($prevNode && $this->_level > 1) {
143
+                    // print(str_pad("", $this->_level, " ") . "{$node->nodeName} creating parent {$prevNode->nodeName}" . "\n");
144
+                    $this->writeNode($prevNode, true);
145
+                    $prevNode = null;
146
+                }
147
+                if (!$this->_traverseDom($node)) {
148
+                    // print(str_pad("", $this->_level, " ") . "{$node->nodeName} content {$node->nodeValue}" . "\n");
149
+                    $data = $node->nodeValue;
150
+                    if (strlen($data) == 0) {
151
+                        $this->writeNode($node);
152
+                    } else {
153
+                        $this->writeNode($node, true, $data);
154
+                        $this->_writeByte(Syncroton_Wbxml_Abstract::END);
155
+                        // print("Closing tag after writing tag\n");
156
+                    }
157
+                } else {
158
+                    $this->_writeByte(Syncroton_Wbxml_Abstract::END);
159
+                    // print("Closing tag\n");
160
+                }
161
+            }
162
         }
163
+        $this->_level--;
164
 
165
-        $this->_attributes = $_attributes;
166
-        
167
+        return $foundElementNode;
168
     }
169
-    
170
+
171
     /**
172
      * strip uri: from nameSpace
173
      *
174
@@ -224,73 +181,6 @@
175
     }
176
     
177
     /**
178
-     * get's called by xml parser when tag ends
179
-     *
180
-     * @param resource $_parser
181
-     * @param string $_tag current tag prefixed with namespace
182
-     */
183
-    protected function _handleEndTag($_parser, $_tag)
184
-    {
185
-        #echo "$_tag Level: $this->_level == $this->_nextStackPop \n";
186
-        
187
-        if($this->_nextStackPop !== NULL && $this->_nextStackPop == $this->_level) {
188
-            #echo "TAG: $_tag\n";
189
-            $this->_writeByte(Syncroton_Wbxml_Abstract::END);
190
-            
191
-            $subStream = $this->_stream;
192
-            $subStreamLength = ftell($subStream);
193
-            
194
-            $this->_dtd             = array_pop($this->_dtdStack);
195
-            $this->_stream          = array_pop($this->_streamStack);
196
-            $this->_nextStackPop    = array_pop($this->_popStack);
197
-            $this->_codePage        = $this->_dtd->getCurrentCodePage();
198
-            
199
-            rewind($subStream);
200
-            #while (!feof($subStream)) {$buffer = fgets($subStream, 4096);echo $buffer;}
201
kolab-syncroton-2.3.23.tar.gz/lib/kolab_sync.php -> kolab-syncroton-2.4.0.tar.gz/lib/kolab_sync.php Changed
20
 
1
@@ -48,7 +48,7 @@
2
     public $task = null;
3
 
4
     const CHARSET = 'UTF-8';
5
-    const VERSION = "2.3.22";
6
+    const VERSION = "2.4.0";
7
 
8
 
9
     /**
10
@@ -301,7 +301,8 @@
11
         // parse $host
12
         $a_host = parse_url($host);
13
         $port = null;
14
-        if ($a_host'host') {
15
+        $ssl = null;
16
+        if (!empty($a_host'host')) {
17
             $host = $a_host'host';
18
             $ssl = (isset($a_host'scheme') && in_array($a_host'scheme', array('ssl','imaps','tls'))) ? $a_host'scheme' : null;
19
             if (!empty($a_host'port')) {
20
kolab-syncroton-2.3.23.tar.gz/lib/kolab_sync_backend.php -> kolab-syncroton-2.4.0.tar.gz/lib/kolab_sync_backend.php Changed
31
 
1
@@ -176,7 +176,7 @@
2
             }
3
 
4
             // Activesync folder identifier (serverId)
5
-            $folder_type = $typedata$folder ?: 'mail';
6
+            $folder_type = ($typedata$folder ?? null) ?: 'mail';
7
             $folder_id   = self::folder_id($folder, $folder_type);
8
 
9
             $folders_list$folder_id = $this->folder_data($folder, $folder_type);
10
@@ -417,10 +417,7 @@
11
     public function device_get($id)
12
     {
13
         $devices_list = $this->devices_list();
14
-
15
-        $result = $devices_list$id;
16
-
17
-        return $result;
18
+        return $devices_list$id ?? null;
19
     }
20
 
21
     /**
22
@@ -670,7 +667,7 @@
23
                 continue;
24
             }
25
 
26
-            $type = $foldertypes$folder ?: 'mail';
27
+            $type = ($foldertypes$folder ?? null) ?: 'mail';
28
             if ($type == 'mail' && isset($special_folders$folder)) {
29
                 $type = $special_folders$folder;
30
             }
31
kolab-syncroton-2.3.23.tar.gz/lib/kolab_sync_backend_common.php -> kolab-syncroton-2.4.0.tar.gz/lib/kolab_sync_backend_common.php Changed
25
 
1
@@ -151,6 +151,10 @@
2
 
3
         $result = $this->db->query('DELETE FROM `' . $this->table_name .'` WHERE `id` = ?', array($id));
4
 
5
+        if ($this->db->is_error($result)) {
6
+            throw new Exception('Failed to delete instance of ' . $this->interface_name);
7
+        }
8
+
9
         return (bool) $this->db->affected_rows($result);
10
     }
11
 
12
@@ -175,8 +179,11 @@
13
             $set = $this->db->quote_identifier($key) . ' = ?';
14
         }
15
 
16
-        $this->db->query('UPDATE `' . $this->table_name . '` SET ' . implode(', ', $set)
17
+        $result = $this->db->query('UPDATE `' . $this->table_name . '` SET ' . implode(', ', $set)
18
             . ' WHERE `id` = ' . $this->db->quote($object->id), array_values($data));
19
+        if ($this->db->is_error($result)) {
20
+            throw new Exception('Failed to update instance of ' . $this->interface_name);
21
+        }
22
 
23
         return $object;
24
     }
25
kolab-syncroton-2.3.23.tar.gz/lib/kolab_sync_backend_state.php -> kolab-syncroton-2.4.0.tar.gz/lib/kolab_sync_backend_state.php Changed
59
 
1
@@ -180,21 +180,27 @@
2
         $where'folder_id'  = $this->db->quote_identifier('folder_id')  . ' = ' . $this->db->quote($folder_id);
3
         $where'is_deleted' = $this->db->quote_identifier('is_deleted') . ' = 1';
4
 
5
-        // found more recent synckey => the last sync response got not received by the client
6
+        // found more recent synckey => the last sync response was not received by the client
7
         if ($next > $sync_key) {
8
-            $where'synckey' = $this->db->quote_identifier('creation_synckey') . ' = ' . $this->db->quote($state->counter);
9
-            // undelete entries marked as deleted in syncroton_content table
10
-            $this->db->query("UPDATE `syncroton_content` SET `is_deleted` = 0 WHERE " . implode(' AND ', $where));
11
-
12
-            // remove entries added during latest sync in syncroton_content table
13
-            unset($where'is_deleted');
14
-            $where'synckey' = $this->db->quote_identifier('creation_synckey') . ' > ' . $this->db->quote($state->counter);
15
-
16
-            $this->db->query("DELETE FROM `syncroton_content` WHERE " . implode(' AND ', $where));
17
+            // We store the clientIdMap with the "next" sync state, so we need to copy it back.
18
+            $state->clientIdMap = $states$next->clientIdMap;
19
         }
20
         else {
21
             // finaly delete all entries marked for removal in syncroton_content table
22
-            $this->db->query("DELETE FROM `syncroton_content` WHERE " . implode(' AND ', $where));
23
+            $retryCounter = 0;
24
+            while(True) {
25
+                $result = $this->db->query("DELETE FROM `syncroton_content` WHERE " . implode(' AND ', $where));
26
+                if ($this->db->is_error($result)) {
27
+                    $retryCounter++;
28
+                    if ($retryCounter > 5) {
29
+                        throw new Exception('Failed to delete entries in sync_key check');
30
+                    }
31
+                } else {
32
+                    break;
33
+                }
34
+                //Give the other transactions some time before we try again
35
+                sleep(1);
36
+            }
37
         }
38
 
39
         // remove all other synckeys
40
@@ -204,4 +210,18 @@
41
 
42
         return $state;
43
     }
44
+
45
+    public function haveNext($deviceid, $folderid, $sync_key)
46
+    {
47
+        $device_id = $deviceid instanceof Syncroton_Model_IDevice ? $deviceid->id : $deviceid;
48
+        $folder_id = $folderid instanceof Syncroton_Model_IFolder ? $folderid->id : $folderid;
49
+
50
+        $where'device_id' = $this->db->quote_identifier('device_id') . ' = ' . $this->db->quote($device_id);
51
+        $where'type'      = $this->db->quote_identifier('type')      . ' = ' . $this->db->quote($folder_id);
52
+        $where'counter'      = $this->db->quote_identifier('counter')      . ' > ' . $this->db->quote($sync_key);
53
+
54
+        $select = $this->db->query("SELECT id FROM `{$this->table_name}` WHERE " . implode(' AND ', $where));
55
+        return $this->db->num_rows($select) > 0;
56
+    }
57
+
58
 }
59
kolab-syncroton-2.3.23.tar.gz/lib/kolab_sync_data.php -> kolab-syncroton-2.4.0.tar.gz/lib/kolab_sync_data.php Changed
55
 
1
@@ -1011,7 +1011,7 @@
2
         }
3
 
4
         // convert categories into tags, save them after creating an object
5
-        if (isset($this->tag_categories) && $this->tag_categories) {
6
+        if (!empty($data'categories') && isset($this->tag_categories) && $this->tag_categories) {
7
             $tags = $data'categories';
8
             unset($data'categories');
9
         }
10
@@ -1462,16 +1462,17 @@
11
      * @param int   $type Result data type (to which the body will be converted, if specified).
12
      *                    One or array of Syncroton_Model_EmailBody constants.
13
      *
14
-     * @return string Body value
15
+     * @return string|null Body value
16
      */
17
     protected function getBody($body, $type = null)
18
     {
19
+        $data = null;
20
         if ($body && $body->data) {
21
             $data = $body->data;
22
         }
23
 
24
         if (!$data || empty($type)) {
25
-            return;
26
+            return null;
27
         }
28
 
29
         $type = (array) $type;
30
@@ -1813,17 +1814,20 @@
31
         // handle exceptions from recurrence
32
         if (!empty($data->exceptions)) {
33
             foreach ($data->exceptions as $exception) {
34
+                $date = clone $exception->exceptionStartTime;
35
+                if ($timezone) {
36
+                    $date->setTimezone($timezone);
37
+                }
38
+
39
                 if ($exception->deleted) {
40
-                    $date = clone $exception->exceptionStartTime;
41
-                    if ($timezone) {
42
-                        $date->setTimezone($timezone);
43
-                    }
44
                     $date->setTime(0, 0, 0);
45
                     $rrule'EXDATE' = $date;
46
                 }
47
                 else {
48
                     $ex = $this->toKolab($exception, $folderid, null, $timezone);
49
 
50
+                    $ex'recurrence_date' = $date;
51
+
52
                     if ($data->allDayEvent) {
53
                         $ex'allday' = 1;
54
                     }
55
kolab-syncroton-2.3.23.tar.gz/lib/kolab_sync_data_calendar.php -> kolab-syncroton-2.4.0.tar.gz/lib/kolab_sync_data_calendar.php Changed
106
 
1
@@ -236,17 +236,15 @@
2
                 break;
3
 
4
             case 'sensitivity':
5
-                if (empty($value)) {
6
-                    continue;
7
+                if (!empty($value)) {
8
+                    $value = intval($this->sensitivityMap$value);
9
                 }
10
-                $value = intval($this->sensitivityMap$value);
11
                 break;
12
 
13
             case 'free_busy':
14
-                if (empty($value)) {
15
-                    continue;
16
+                if (!empty($value)) {
17
+                    $value = $this->busyStatusMap$value;
18
                 }
19
-                $value = $this->busyStatusMap$value;
20
                 break;
21
 
22
             case 'description':
23
@@ -495,7 +493,8 @@
24
         else if (isset($data->attendees)) {
25
             $statusMap = array_flip($this->attendeeStatusMap);
26
             foreach ($data->attendees as $attendee) {
27
-                if ($attendee->email && $attendee->email == $organizer_email) {
28
+                if (!empty($organizer_email) && $attendee->email && !strcasecmp($attendee->email, $organizer_email)) {
29
+                    // skip the organizer
30
                     continue;
31
                 }
32
 
33
@@ -540,22 +539,23 @@
34
             }
35
         }
36
 
37
-        // Make sure the event has the organizer set
38
-        if (!$organizer_email && ($identity = kolab_sync::get_instance()->user->get_identity())) {
39
-            $attendees = array(
40
-                'role'  => 'ORGANIZER',
41
-                'name'  => $identity'name',
42
-                'email' => $identity'email',
43
-            );
44
+        if (!$is_exception) {
45
+            // Make sure the event has the organizer set
46
+            if (!$organizer_email && ($identity = kolab_sync::get_instance()->user->get_identity())) {
47
+                $attendees = array(
48
+                    'role'  => 'ORGANIZER',
49
+                    'name'  => $identity'name',
50
+                    'email' => $identity'email',
51
+                );
52
+            }
53
+
54
+            // recurrence (and exceptions)
55
+            $event'recurrence' = $this->recurrence_to_kolab($data, $folderid, $timezone);
56
         }
57
 
58
         $event'attendees'  = $attendees;
59
         $event'categories' = $categories;
60
-
61
-        // recurrence (and exceptions)
62
-        if (!$is_exception) {
63
-            $event'recurrence' = $this->recurrence_to_kolab($data, $folderid, $timezone);
64
-        }
65
+        $event'exceptions' = isset($event'recurrence''EXCEPTIONS') ? $event'recurrence''EXCEPTIONS' : array();
66
 
67
         // Bump SEQUENCE number on update (Outlook only).
68
         // It's been confirmed that any change of the event that has attendees specified
69
@@ -807,14 +807,13 @@
70
      */
71
     protected function update_attendee_status(&$event, $status)
72
     {
73
-        $organizer = null;
74
-        $emails    = $this->user_emails();
75
+        $emails = $this->user_emails();
76
 
77
         foreach ((array) $event'attendees' as $i => $attendee) {
78
-            if ($attendee'role' == 'ORGANIZER') {
79
-                $organizer = $attendee;
80
-            }
81
-            else if ($attendee'email' && in_array_nocase($attendee'email', $emails)) {
82
+            if (!empty($attendee'email')
83
+                && (empty($attendee'role') || $attendee'role' != 'ORGANIZER')
84
+                && in_array_nocase($attendee'email', $emails)
85
+            ) {
86
                 $event'attendees'$i'status' = $status;
87
                 $event'attendees'$i'rsvp'   = false;
88
                 $event_attendee = $attendee;
89
@@ -822,8 +821,14 @@
90
         }
91
 
92
         if (!$event_attendee) {
93
-            $this->logger->warn('MeetingResponse on an event where the user is not an attendee. UID: ' . $event'uid');
94
-            throw new Syncroton_Exception_Status_MeetingResponse(Syncroton_Exception_Status_MeetingResponse::MEETING_ERROR);
95
+            // Add the user to the attendees list
96
+            $event'attendees' = array(
97
+                'role'   => 'OPT-PARTICIPANT',
98
+                'name'   => '',
99
+                'email'  => $emails0,
100
+                'status' => $status,
101
+                'rsvp'   => false,
102
+            );
103
         }
104
     }
105
 
106
kolab-syncroton-2.3.23.tar.gz/lib/kolab_sync_data_email.php -> kolab-syncroton-2.4.0.tar.gz/lib/kolab_sync_data_email.php Changed
9
 
1
@@ -283,6 +283,7 @@
2
         // In Sync examples there's one in which bodyPreferences is not defined
3
         // in such case Truncated=1 and there's no body sent to the client
4
         // only it's estimated size
5
+        $isTruncated = 0;
6
         if (empty($prefs)) {
7
             $messageBody = '';
8
             $real_length = $headers->size;
9
kolab-syncroton-2.3.23.tar.gz/lib/kolab_sync_data_tasks.php -> kolab-syncroton-2.4.0.tar.gz/lib/kolab_sync_data_tasks.php Changed
49
 
1
@@ -140,7 +140,9 @@
2
                 break;
3
 
4
             case 'sensitivity':
5
-                $value = intval($this->sensitivityMap$value);
6
+                if (!empty($value)) {
7
+                    $value = intval($this->sensitivityMap$value);
8
+                }
9
                 break;
10
 
11
             case 'priority':
12
@@ -156,7 +158,9 @@
13
         }
14
 
15
         // convert kolab tags into categories
16
-        $result'categories' = $this->getKolabTags($task'uid', $result'categories');
17
+        if (!empty($result'categories')) {
18
+            $result'categories' = $this->getKolabTags($task'uid', $result'categories');
19
+        }
20
 
21
         // Recurrence
22
         $this->recurrence_from_kolab($collection, $task, $result, 'Task');
23
@@ -222,7 +226,7 @@
24
 
25
             case 'sensitivity':
26
                 $map   = array_flip($this->sensitivityMap);
27
-                $value = $map$value;
28
+                $value = $map$value ?? 'none' ?? self::SENSITIVITY_NORMAL;
29
                 break;
30
 
31
             case 'description':
32
@@ -245,9 +249,13 @@
33
             $task'status'   = 'COMPLETED';
34
             $task'complete' = 100;
35
         }
36
-        else if (isset($data->complete) && ($task'status' == 'COMPLETED' || $task'complete' == 100)) {
37
-            $task'status'   = '';
38
-            $task'complete' = 0;
39
+        else if (isset($data->complete)) {
40
+            if ((!empty($task'status') && $task'status' == 'COMPLETED')
41
+                || (!empty($task'complete') && $task'complete' == 100)
42
+            ) {
43
+                $task'status'   = '';
44
+                $task'complete' = 0;
45
+            }
46
         }
47
 
48
         // recurrence
49
kolab-syncroton-2.4.0.tar.gz/tests/wbxml.php Added
201
 
1
@@ -0,0 +1,888 @@
2
+<?php
3
+
4
+class message extends PHPUnit\Framework\TestCase
5
+{
6
+    //function testDecode()
7
+    //{
8
+    //    //TODO input some wbxml document
9
+    //    //
10
+    //        $dom = new DOMDocument();
11
+    //        $dom->loadXML($lastSyncCollection'lastXML');
12
+    //    //
13
+    //        try {
14
+    //            $decoder = new Syncroton_Wbxml_Decoder($dom);
15
+    //            $requestBody = $decoder->decode();
16
+    //            if ($this->_logger instanceof Zend_Log) {
17
+    //                $requestBody->formatOutput = true;
18
+    //                $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " xml request:\n" . $requestBody->saveXML());
19
+    //            }
20
+    //        } catch(Syncroton_Wbxml_Exception_UnexpectedEndOfFile $e) {
21
+    //            $requestBody = NULL;
22
+    //        }
23
+    //    //TODO validate output
24
+    //}
25
+
26
+
27
+
28
+    public function testEncode()
29
+    {
30
+        $outputStream = fopen("php://temp", 'r+');
31
+        
32
+        $encoder = new Syncroton_Wbxml_Encoder($outputStream, 'UTF-8', 3);
33
+
34
+        $xml = <<<EOF
35
+        <?xml version="1.0" encoding="utf-8"?>
36
+        <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/">
37
+        <Sync xmlns="uri:AirSync" xmlns:AirSyncBase="uri:AirSyncBase" xmlns:Tasks="uri:Tasks">
38
+            <Collections>
39
+                <Collection>
40
+                    <SyncKey>2</SyncKey>
41
+                    <CollectionId>tasksId</CollectionId>
42
+                    <Commands>
43
+                        <Add>
44
+                            <ClientId>clientId2</ClientId>
45
+                            <ApplicationData>
46
+                                <Subject xmlns="uri:Tasks">task2</Subject>
47
+                                <Complete xmlns="uri:Tasks">0</Complete>
48
+                                <DueDate xmlns="uri:Tasks">2020-11-04T00:00:00.000Z</DueDate>
49
+                                <UtcDueDate xmlns="uri:Tasks">2020-11-03T23:00:00.000Z</UtcDueDate>
50
+                            </ApplicationData>
51
+                        </Add>
52
+                        <Add>
53
+                            <ClientId>clientId3</ClientId>
54
+                            <ApplicationData>
55
+                                <Subject xmlns="uri:Tasks">task3</Subject>
56
+                                <Complete xmlns="uri:Tasks">0</Complete>
57
+                                <DueDate xmlns="uri:Tasks">2020-11-04T00:00:00.000Z</DueDate>
58
+                                <UtcDueDate xmlns="uri:Tasks">2020-11-03T23:00:00.000Z</UtcDueDate>
59
+                            </ApplicationData>
60
+                        </Add>
61
+                    </Commands>
62
+                </Collection>
63
+            </Collections>
64
+            <WindowSize>16</WindowSize>
65
+        </Sync>
66
+        EOF;
67
+
68
+
69
+        $dom = new DOMDocument();
70
+        $dom->loadXML($xml);
71
+        
72
+        $encoder->encode($dom);
73
+
74
+        rewind($outputStream);
75
+        $output = stream_get_contents($outputStream);
76
+        // print("----");
77
+        // print(var_export($output, true));
78
+        // print("----");
79
+        $this->assertEquals(
80
+            base64_decode('AwFqAEVcT0sDMgABUgN0YXNrc0lkAAFWR0wDY2xpZW50SWQyAAFdAAlgA3Rhc2syAAFKAzAAAUwDMjAyMC0xMS0wNFQwMDowMDowMC4wMDBaAAFNAzIwMjAtMTEtMDNUMjM6MDA6MDAuMDAwWgABAQEAAEdMA2NsaWVudElkMwABXQAJYAN0YXNrMwABSgMwAAFMAzIwMjAtMTEtMDRUMDA6MDA6MDAuMDAwWgABTQMyMDIwLTExLTAzVDIzOjAwOjAwLjAwMFoAAQEBAQEBAABVAzE2AAEB'),
81
+            $output
82
+        );
83
+    }
84
+
85
+    public function testEncodeFolderSync()
86
+    {
87
+        $outputStream = fopen("php://temp", 'r+');
88
+        
89
+        $encoder = new Syncroton_Wbxml_Encoder($outputStream, 'UTF-8', 3);
90
+
91
+        $xml = <<<EOF
92
+        <?xml version="1.0" encoding="utf-8"?>
93
+        <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/">
94
+        <FolderSync xmlns="uri:FolderHierarchy" xmlns:Syncroton="uri:Syncroton" xmlns:Internal="uri:Internal">
95
+        <Status>1</Status>
96
+        <SyncKey>1</SyncKey>
97
+        <Changes>
98
+            <Count>18</Count>
99
+            <Add>
100
+            <ServerId>2685b302b79f58d2753199545e3cb8be</ServerId>
101
+            <ParentId>0</ParentId>
102
+            <DisplayName>Test2</DisplayName>
103
+            <Type>13</Type>
104
+            </Add>
105
+            <Add>
106
+            <ServerId>9770b083c68e8584f396d15a116d6608</ServerId>
107
+            <ParentId>0</ParentId>
108
+            <DisplayName>DavidCalendar</DisplayName>
109
+            <Type>13</Type>
110
+            </Add>
111
+            <Add>
112
+            <ServerId>0f66388806743c514b8063bf0dc87486</ServerId>
113
+            <ParentId>0</ParentId>
114
+            <DisplayName>SergeyCalendar</DisplayName>
115
+            <Type>13</Type>
116
+            </Add>
117
+            <Add>
118
+            <ServerId>cca1b81c734abbcd669bea90d23e08ae</ServerId>
119
+            <ParentId>0</ParentId>
120
+            <DisplayName>Calendar</DisplayName>
121
+            <Type>8</Type>
122
+            </Add>
123
+            <Add>
124
+            <ServerId>ab1ddb4ef8e8f8fcc2c9f5a7f9062452</ServerId>
125
+            <ParentId>0</ParentId>
126
+            <DisplayName>PubCal</DisplayName>
127
+            <Type>13</Type>
128
+            </Add>
129
+            <Add>
130
+            <ServerId>d98bd8721371544ed095841ead941893</ServerId>
131
+            <ParentId>0</ParentId>
132
+            <DisplayName>(david) Test2</DisplayName>
133
+            <Type>13</Type>
134
+            </Add>
135
+            <Add>
136
+            <ServerId>9e7b9656ef61d4af2fb2fdcabe600079</ServerId>
137
+            <ParentId>0</ParentId>
138
+            <DisplayName>(david) DavidCalendar</DisplayName>
139
+            <Type>13</Type>
140
+            </Add>
141
+            <Add>
142
+            <ServerId>384cf2d877c39a622fdc2a16898052e2</ServerId>
143
+            <ParentId>0</ParentId>
144
+            <DisplayName>(david) Calendar</DisplayName>
145
+            <Type>13</Type>
146
+            </Add>
147
+            <Add>
148
+            <ServerId>Contacts::Syncroton</ServerId>
149
+            <ParentId>0</ParentId>
150
+            <DisplayName>Contacts</DisplayName>
151
+            <Type>9</Type>
152
+            </Add>
153
+            <Add>
154
+            <ServerId>1bb8c55fe84d52c6968db2571f7dc124</ServerId>
155
+            <ParentId>0</ParentId>
156
+            <DisplayName>Archive</DisplayName>
157
+            <Type>12</Type>
158
+            </Add>
159
+            <Add>
160
+            <ServerId>b51abe73e9e98fe200a4afe409050502</ServerId>
161
+            <ParentId>38b950ebd62cd9a66929c89615d0fc04</ParentId>
162
+            <DisplayName>Spam</DisplayName>
163
+            <Type>12</Type>
164
+            </Add>
165
+            <Add>
166
+            <ServerId>cf529c792fc87d1f207435b3921bb02e</ServerId>
167
+            <ParentId>0</ParentId>
168
+            <DisplayName>Sent</DisplayName>
169
+            <Type>5</Type>
170
+            </Add>
171
+            <Add>
172
+            <ServerId>715ed9ea29b8a5377a69c1f758037c65</ServerId>
173
+            <ParentId>0</ParentId>
174
+            <DisplayName>Spam</DisplayName>
175
+            <Type>12</Type>
176
+            </Add>
177
+            <Add>
178
+            <ServerId>db0d959a3aeb21757f8849a830947a7a</ServerId>
179
+            <ParentId>0</ParentId>
180
+            <DisplayName>Trash</DisplayName>
181
+            <Type>4</Type>
182
+            </Add>
183
+            <Add>
184
+            <ServerId>5ac9ec2e1a9d99e2e10cabe4abf26729</ServerId>
185
+            <ParentId>0</ParentId>
186
+            <DisplayName>Drafts</DisplayName>
187
+            <Type>3</Type>
188
+            </Add>
189
+            <Add>
190
+            <ServerId>38b950ebd62cd9a66929c89615d0fc04</ServerId>
191
+            <ParentId>0</ParentId>
192
+            <DisplayName>INBOX</DisplayName>
193
+            <Type>2</Type>
194
+            </Add>
195
+            <Add>
196
+            <ServerId>fc56f4c7ffe0aefa622db9f8d9186c4a</ServerId>
197
+            <ParentId>0</ParentId>
198
+            <DisplayName>Notes</DisplayName>
199
+            <Type>10</Type>
200
+            </Add>
201
kolab-syncroton.dsc Changed
17
 
1
@@ -2,7 +2,7 @@
2
 Source: kolab-syncroton
3
 Binary: kolab-syncroton
4
 Architecture: all
5
-Version: 2.3.23-1~kolab1
6
+Version: 2.4.0-1~kolab1
7
 Maintainer: Jeroen van Meeuwen <vanmeeuwen@kolabsys.com>
8
 Uploaders: Jeroen van Meeuwen <vanmeeuwen@kolabsys.com>
9
 Homepage: http://www.kolab.org/
10
@@ -12,5 +12,5 @@
11
 Package-List:
12
  kolab-syncroton deb utils extra
13
 Files:
14
- 00000000000000000000000000000000 0 kolab-syncroton-2.3.23.tar.gz
15
+ 00000000000000000000000000000000 0 kolab-syncroton-2.4.0.tar.gz
16
  00000000000000000000000000000000 0 debian.tar.gz
17
plesk.kolab_syncroton.inc.php Changed
10
 
1
@@ -118,8 +118,6 @@
2
 $config'activesync_multifolder_blacklist_note' = null;
3
 $config'activesync_multifolder_blacklist_task' = null;
4
 
5
-$config'activesync_protected_folders' = array('windowsoutlook' => array('INBOX', 'Sent', 'Trash'));
6
-
7
 // Enables adding sender name in the From: header of send email
8
 // when a device uses email address only (e.g. iOS devices)
9
 $config'activesync_fix_from' = true;
10