IMAP Backend: folder rename show duplicate folder on client
-
Hi team,
I saw that rename folder at ChangeFolder function was not implemented.// TODO this would be solved by implementing hex ids (Mantis #459) //$csts = imap_renamemailbox($this->mbox, $this->server . imap_utf7_encode(str_replace(".", $this->getServerDelimiter(), $oldid)), $newname);
I tried to change this function, but something wrong happening, I can rename the folder, but at next sync, the folder appearing duplicated at the client.
There are the changes in source code:
public function ChangeFolder($folderid, $oldid, $displayname, $type){ ZLog::Write(LOGLEVEL_INFO, sprintf("BackendIMAP->ChangeFolder('%s','%s','%s','%s')", $folderid, $oldid, $displayname, $type)); // if $id is set => rename mailbox, otherwise create if ($oldid) { // rename doesn't work properly with IMAP // the activesync client doesn't support a 'changing ID' // TODO this would be solved by implementing hex ids (Mantis #459) //$csts = imap_renamemailbox($this->mbox, $this->server . imap_utf7_encode(str_replace(".", $this->getServerDelimiter(), $oldid)), $newname); /** * DBLONGO changes start here!!! (TENTATIVE) */ // Compatibility: if using Combined Backend, it gives 'backends' letter and delimiter. Example: i/123456 $tmp = explode('/', $oldid); if(is_array($tmp)) $oldid = $tmp[1]; // Gets the source folder name in IMAP format $oldimapid = $this->getImapIdFromFolderId($oldid); // Gets the target folder name in IMAP format $imapid = $this->getImapIdFromFolderId($folderid); // Append displayname at the target folder $newimapid = $imapid . $this->getServerDelimiter() . $displayname; // Simplifying "imap_renamemailbox" command $source = $this->server . imap_utf7_encode(str_replace(".", $this->getServerDelimiter(), $oldimapid)); $target = $this->server . imap_utf7_encode(str_replace(".", $this->getServerDelimiter(), $newimapid)); // Unsubscribe source folder before move imap_unsubscribe($this->mbox, $source); // Renames the folder. $csts = imap_renamemailbox($this->mbox, $source, $target); if($csts){ // Using the same criteria of imap_createmailbox $newid = $this->convertImapId($newimapid); return $this->StatFolder($newid); } /** * DBLONGO changes end here!!! */ ZLog::Write(LOGLEVEL_ERROR, "BackendIMAP->ChangeFolder() : we do not support rename for now"); return false; } else { // build name for new mailboxBackendMaildir $displayname = Utils::Utf8_to_utf7imap($displayname); if ($folderid == "0") { $newimapid = $displayname; } else { $imapid = $this->getImapIdFromFolderId($folderid); $newimapid = $imapid . $this->getServerDelimiter() . $displayname; } $csts = imap_createmailbox($this->mbox, $this->server . $newimapid); ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendIMAP->ChangeFolder() createmailbox: '%s'", $newimapid)); if ($csts) { imap_subscribe($this->mbox, $this->server . $newimapid); $newid = $this->convertImapId($newimapid); return $this->StatFolder($newid); } else { ZLog::Write(LOGLEVEL_WARN, "BackendIMAP->ChangeFolder() : mailbox creation failed"); return false; } } }
Did I do something wrong?
Thanks so much!
-
Hi dblongo,
I’m not very familiar with the imap backend code and how exactly it works internally, so I only guess that removing of the old folderid from the hierarchy is missing.
Where are you renaming the folder? On the server or on the mobile device?
Manfred
-
Hi Mandred!
I trying to remove from mobile device.
I tried to do that in importchangesdiff.php, forcing delete of old $folderid when return of ChangeFolder function, but no success.$this->updateState(“delete”, array(“id”=>$id);
Sorry for the question, but how do I remove it?
Thanks so much!
-
Hi dblongo,
sorry, but I don’t know the exact details to tell you what’s missing.
Does the server renames the folder correctly with your changes?
If you renaming it on the mobile, so mobile actually knows about the change. I guess there’s something missing on the Z-Push side. Maybe something in the states or the persistent storage where id mapping takes places. You’ll have to to some search where the old id is still in place.
Manfred
-
Hi Manfred,
The server renames correctly. If you allow me, can I send the log summary here?
I’ve been working hard on it for many days but I think it’s something very simple.
Please help me… -
Hi dblongo,
yes, you can post the logs here. If not me, maybe someone else will have an idea.
Manfred
-
From yesterday to today I made some changes and I think things have improved a bit. I used the same $oldid for the renamed folder.
Now, the folder does not appear duplicated anymore, but if I move the folder back to the inbox, it changes on the server, but on mobile, on next synchronization it goes back to the source folder.There are code changed:
/** * Start DBLONGO changes (TENTATIVE) */ // Compatibility: if using Combined Backend, it gives 'backends' letter and delimiter. Example: i/123456 $tmp = explode('/', $oldid); if(is_array($tmp) && count($tmp)>1) $oldid = $tmp[1]; // Gets the source folder name in IMAP format $oldimapid = $this->getImapIdFromFolderId($oldid); // Gets the target folder name in IMAP format $imapid = $this->getImapIdFromFolderId($folderid); // Append displayname at the target folder $newimapid = $imapid . $this->getServerDelimiter() . $displayname; // Simplifying "imap_renamemailbox" command $source = $this->server . imap_utf7_encode(str_replace(".", $this->getServerDelimiter(), $oldimapid)); $target = $this->server . imap_utf7_encode(str_replace(".", $this->getServerDelimiter(), $newimapid)); // Unsubscribe source folder before move // imap_unsubscribe($this->mbox, $source); // Renames the folder. $csts = imap_renamemailbox($this->mbox, $source, $target); if($csts){ // $this->convertImapId($newimapid); $newid = $oldid; // Replace old IMAP Folder at fmfidfimap: [HEX] = New IMAP Folder $a = $this->permanentStorage->fmfidfimap; if(isset($a[$oldid])) $a[$oldid] = $newimapid; $this->permanentStorage->fmfidfimap = $a; // Remove old IMAP Folder at fmFimapFid: [IMAPFolder] = HEX $a = $this->permanentStorage->fmFimapFid; if(isset($a[$oldimapid])) unset($a[$oldimapid]); // Add new IMAP Folder at fmFimapFid: [IMAPFolder] = HEX if(!isset($a[$newimapid])) $a[$newimapid] = $newid; $this->permanentStorage->fmFimapFid = $a; // Remove old IMAP Folder at fmfimapfidlowercase: [imapfolder] = HEX $a = $this->permanentStorage->fmfimapfidlowercase; if(isset($a[strtolower($oldimapid)])) unset($a[strtolower($oldimapid)]); // Add new IMAP Folder at fmfimapfidlowercase: [imapfolder] = HEX if(!isset($a[strtolower($newimapid)])) $a[strtolower($newimapid)] = $newid; $this->permanentStorage->fmfimapfidlowercase = $a; // Only tentatives, but did not worked too //$this->changessinkinit = false; //$this->ChangesSinkInitialize($newid); //$this->SaveStorages(); return $this->StatFolder($newid); } /** * End DBLONGO changes */
I’m going to post the logs in 2 replies because the text is a bit big:
-
When I rename the “Folder1” at INBOX to the Trash. It’s works.
-
When I move “Folder1” back to INBOX, the folder is renamed at IMAP server, however, at the next synchronization “Folder1” backs to source folder.
On the logs, I changed the HEX codes of folderID to folder names to be more clean.
Please, someone can help me?
-
-
- When I rename the “Folder1” at INBOX to the Trash. It’s works.
[WBXML] I FolderHierarchy:FolderUpdate
[WBXML] I FolderHierarchy:SyncKey
[WBXML] I {a234337d-c081-4f9b-8595-cf7888cb3cc7}1
[WBXML] I </FolderHierarchy:SyncKey>
[WBXML] I FolderHierarchy:ServerEntryId
[WBXML] I Folder1
[WBXML] I </FolderHierarchy:ServerEntryId>
[WBXML] I FolderHierarchy:ParentId
[WBXML] I Trash
[WBXML] I </FolderHierarchy:ParentId>
[WBXML] I FolderHierarchy:DisplayName
[WBXML] I Folder1
[WBXML] I </FolderHierarchy:DisplayName>
[WBXML] I </FolderHierarchy:FolderUpdate>// imap.php: BackendIMAP::ChangeFolder: ChangeFolder(‘Trash’, ‘Folder1’, ‘Folder1’, ‘12’)
// SOURCE: {mail.dblongo.com:143/imap/notls/norsh}INBOX/Folder1
// TARGET: {mail.dblongo.com:143/imap/notls/norsh}Trash/Folder1// StateObject Object: Before folder rename
[SO_internalid:StateObject:private] => 472fbf818187 [data:protected] => Array ( [fmfidfimap] => Array ( [INBOX] => INBOX [Folder1] => INBOX/Folder1 [Trash] => Trash ) [fmfimapfid] => Array ( [INBOX] => INBOX [INBOX/Folder1] => Folder1 [Trash] => Trash ) [fmfimapfidlowercase] => Array ( [inbox] => INBOX [inbox/folder1] => Folder1 [trash] => Trash ) [serverdelimiter] => / )
// StateObject Object: After folder rename
[SO_internalid:StateObject:private] => 472fbf818187 [data:protected] => Array ( [fmfidfimap] => Array ( [INBOX] => INBOX [Folder1] => Trash/Folder1 [Trash] => Trash ) [fmfimapfid] => Array ( [INBOX] => INBOX [Trash] => Trash [Trash/Folder1] => Folder1 ) [fmfimapfidlowercase] => Array ( [inbox] => INBOX [trash] => Trash [trash/folder1] => Folder1 ) [serverdelimiter] => / )
// ImportChangesDiff::ImportFolderChange()
// SyncFolder Object:[serverid] => Folder1 [parentid] => Trash [displayname] => Folder1 [type] => 12 [Store] => [NoBackendFolder] => [BackendId] => Folder1 [Flags] => [TypeReal] => [flags] => [content] =>
[WBXML] O FolderHierarchy:FolderUpdate
[WBXML] O FolderHierarchy:Status
[WBXML] O 1
[WBXML] O </FolderHierarchy:Status>
[WBXML] O FolderHierarchy:SyncKey
[WBXML] O {a234337d-c081-4f9b-8595-cf7888cb3cc7}2
[WBXML] O </FolderHierarchy:SyncKey>
[WBXML] O </FolderHierarchy:FolderUpdate>
[WBXML] O Ping:Ping
[WBXML] O Ping:Status
[WBXML] O 7
[WBXML] O </Ping:Status>
[WBXML] O </Ping:Ping>[DEBUG] -------- Start
[WBXML] I FolderHierarchy:FolderSync
[WBXML] I FolderHierarchy:SyncKey
[WBXML] I {a234337d-c081-4f9b-8595-cf7888cb3cc7}2
[WBXML] I </FolderHierarchy:SyncKey>
[WBXML] I </FolderHierarchy:FolderSync>[DEBUG] ChangesMemoryWrapper->ImportFolderChange(): Change for folder ‘Inbox’ will not be sent as modification is not relevant.
[DEBUG] BackendIMAP->getImapIdFromFolderId(‘Folder1’) = Trash/Folder1
[DEBUG] BackendIMAP->getFolderIdFromImapId(‘Trash’) = Trash
[DEBUG] BackendIMAP->convertImapId(‘Trash’) = Trash
[DEBUG] BackendIMAP->GetFolder(‘Folder1’): ‘SyncFolder (
(S) serverid => Folder1
(S) parentid => Trash
(S) displayname => Folder1
(S) type => 12
(S) Store => null
(S) NoBackendFolder => null
(S) BackendId => null
(S) Flags => null
(S) TypeReal => null
unsetVars(Array) size: 0
supportsPrivateStripping => false
flags => false
content => null
)’
[DEBUG] SyncObject->equals() false because field ‘BackendId’ is only defined at one obj: ‘false’ != ‘true’
[DEBUG] HierarchyCache: AddFolder() serverid: Folder1 displayname: Folder1[WBXML] O FolderHierarchy:FolderSync
[WBXML] O FolderHierarchy:Status
[WBXML] O 1
[WBXML] O </FolderHierarchy:Status>
[WBXML] O FolderHierarchy:SyncKey
[WBXML] O {a234337d-c081-4f9b-8595-cf7888cb3cc7}3
[WBXML] O </FolderHierarchy:SyncKey>
[WBXML] O FolderHierarchy:Changes
[WBXML] O FolderHierarchy:Count
[WBXML] O 1
[WBXML] O </FolderHierarchy:Count>
[WBXML] O FolderHierarchy:Update
[WBXML] O FolderHierarchy:ServerEntryId
[WBXML] O Folder1
[WBXML] O </FolderHierarchy:ServerEntryId>
[WBXML] O FolderHierarchy:ParentId
[WBXML] O Trash
[WBXML] O </FolderHierarchy:ParentId>
[WBXML] O FolderHierarchy:DisplayName
[WBXML] O Folder1
[WBXML] O </FolderHierarchy:DisplayName>
[WBXML] O FolderHierarchy:Type
[WBXML] O 12
[WBXML] O </FolderHierarchy:Type>
[WBXML] O </FolderHierarchy:Update>
[WBXML] O </FolderHierarchy:Changes> -
- When I move “Folder1” back to INBOX, the folder is renamed at IMAP server, however, at next synchronization “Folder1” backs to source folder.
[WBXML] I FolderHierarchy:FolderUpdate
[WBXML] I FolderHierarchy:SyncKey
[WBXML] I {a234337d-c081-4f9b-8595-cf7888cb3cc7}3
[WBXML] I </FolderHierarchy:SyncKey>
[WBXML] I FolderHierarchy:ServerEntryId
[WBXML] I Folder1
[WBXML] I </FolderHierarchy:ServerEntryId>
[WBXML] I FolderHierarchy:ParentId
[WBXML] I INBOX
[WBXML] I </FolderHierarchy:ParentId>
[WBXML] I FolderHierarchy:DisplayName
[WBXML] I Folder1
[WBXML] I </FolderHierarchy:DisplayName>
[WBXML] I </FolderHierarchy:FolderUpdate>[DEBUG] StateManager->loadHierarchyCache(): ‘DEVICEID12345678-a234337d-c081-4f9b-8595-cf7888cb3cc7-hc-3’
[DEBUG] SqlStateMachine->GetState(): devid:‘DEVICEID12345678’ type:‘hc’ key:‘a234337d-c081-4f9b-8595-cf7888cb3cc7’ counter:‘3’
[DEBUG] SqlStateMachine->CleanStates(): devid:‘DEVICEID12345678’ type:‘hc’ key:‘a234337d-c081-4f9b-8595-cf7888cb3cc7’ counter:‘3’ thisCounterOnly:‘false’// asdevice.php: ASDevice::GetFolderBackendId(‘Folder1’)
[INBOX] => Array ( [2] => 2 [5] => [1] => c9b9d65e-958e-4176-97c2-44a5e720262e ) [Folder1] => Array ( [2] => 12 [5] => ) [Trash] => Array ( [2] => 4 [5] => )
[DEBUG] ASDevice->GetHierarchyCache(): HierarchyCache is up - Cached objects: 3
[DEBUG] ZPush::GetAdditionalSyncFolderStore(‘Folder1’): ‘false’
[DEBUG] ZPush::GetAdditionalSyncFolderStore(‘INBOX’): ‘false’
[DEBUG] ChangesMemoryWrapper->ImportFolderChange(): Set foldertype for folder ‘Folder1’ from cache as it was not sent: ‘12’
[ INFO] BackendIMAP->ChangeFolder(‘INBOX’,‘Folder1’,‘Folder1’,‘12’)
[DEBUG] SqlStateMachine->GetState(): devid:‘DEVICEID12345678’ type:‘bs’ key:‘null’ counter:‘1526667813’// imap.php: BackendIMAP::ChangeFolder: ChangeFolder(‘INBOX’, ‘Folder1’, ‘Folder1’, ‘12’)
// SOURCE: {mail.dblongo.com:143/imap/notls/norsh}Trash/Folder1
// TARGET: {mail.dblongo.com:143/imap/notls/norsh}INBOX/Folder1// StateObject Object: Before rename folder
[SO_internalid:StateObject:private] => 472fbf818187 [data:protected] => Array ( [fmfidfimap] => Array ( [INBOX] => INBOX [Folder1] => Trash/Folder1 [Trash] => Trash ) [fmfimapfid] => Array ( [INBOX] => INBOX [INBOX/Folder1] => Folder1 [Trash] => Trash [Trash/Folder1] => Folder1 ) [fmfimapfidlowercase] => Array ( [inbox] => INBOX [inbox/folder1] => Folder1 [trash] => Trash [trash/folder1] => Folder1 ) [serverdelimiter] => / )
// StateObject Object: After folder rename
[SO_internalid:StateObject:private] => 472fbf818187 [data:protected] => Array ( [fmfidfimap] => Array ( [INBOX] => INBOX [Folder1] => INBOX/Folder1 [Trash] => Trash ) [fmfimapfid] => Array ( [INBOX] => INBOX [INBOX/Folder1] => Folder1 [Trash] => Trash ) [fmfimapfidlowercase] => Array ( [inbox] => INBOX [inbox/folder1] => Folder1 [trash] => Trash ) [serverdelimiter] => / )
// importchangesdiff.php: ImportChangesDiff::ImportFolderChange(’’, ‘’, ‘Folder1’, ‘12’)
// SyncFolder Object[serverid] => Folder1 [parentid] => INBOX [displayname] => Folder1 [type] => 12 [Store] => [NoBackendFolder] => [BackendId] => Folder1 [Flags] => [TypeReal] => [flags] => [content] =>
[DEBUG] BackendIMAP->getImapIdFromFolderId(‘Folder1’) = INBOX/Folder1
[DEBUG] BackendIMAP->getFolderIdFromImapId(‘INBOX’) = INBOX
[DEBUG] BackendIMAP->convertImapId(‘INBOX’) = INBOX
[DEBUG] BackendIMAP->GetFolder(‘Folder1’): ‘SyncFolder (
(S) serverid => Folder1
(S) parentid => INBOX
(S) displayname => Folder1
(S) type => 12
(S) Store => null
(S) NoBackendFolder => null
(S) BackendId => null
(S) Flags => null
(S) TypeReal => null
unsetVars(Array) size: 0
supportsPrivateStripping => false
flags => false
content => null
)’[WBXML] O FolderHierarchy:FolderUpdate
[WBXML] O FolderHierarchy:Status
[WBXML] O 1
[WBXML] O </FolderHierarchy:Status>
[WBXML] O FolderHierarchy:SyncKey
[WBXML] O {a234337d-c081-4f9b-8595-cf7888cb3cc7}4
[WBXML] O </FolderHierarchy:SyncKey>
[WBXML] O </FolderHierarchy:FolderUpdate>[DEBUG] SqlStateMachine->GetState(): devid:‘DEVICEID12345678’ type:‘devicedata’ key:‘null’ counter:‘false’
[WBXML] I FolderHierarchy:FolderSync
[WBXML] I FolderHierarchy:SyncKey
[WBXML] I {a234337d-c081-4f9b-8595-cf7888cb3cc7}4
[WBXML] I </FolderHierarchy:SyncKey>
[WBXML] I </FolderHierarchy:FolderSync>[DEBUG] BackendIMAP->getImapIdFromFolderId(‘Folder1’) = Trash/Folder1
[DEBUG] BackendIMAP->getFolderIdFromImapId(‘Trash’) = Trash
[DEBUG] BackendIMAP->convertImapId(‘Trash’) = Trash
[DEBUG] BackendIMAP->GetFolder(‘Folder1’): ‘SyncFolder (
(S) serverid => Folder1
(S) parentid => Trash
(S) displayname => Folder1
(S) type => 12
(S) Store => null
(S) NoBackendFolder => null
(S) BackendId => null
(S) Flags => null
(S) TypeReal => null
unsetVars(Array) size: 0
supportsPrivateStripping => false
flags => false
content => null
)’
[DEBUG] SyncObject->equals() false on field ‘parentid’: ‘Trash’ != ‘INBOX’ using strictTypeCompare
[DEBUG] HierarchyCache: AddFolder() serverid: Folder1 displayname: Folder1[WBXML] O FolderHierarchy:FolderSync
[WBXML] O FolderHierarchy:Status
[WBXML] O 1
[WBXML] O </FolderHierarchy:Status>
[WBXML] O FolderHierarchy:SyncKey
[WBXML] O {a234337d-c081-4f9b-8595-cf7888cb3cc7}5
[WBXML] O </FolderHierarchy:SyncKey>
[WBXML] O FolderHierarchy:Changes
[WBXML] O FolderHierarchy:Count
[WBXML] O 1
[WBXML] O </FolderHierarchy:Count>
[WBXML] O FolderHierarchy:Update
[WBXML] O FolderHierarchy:ServerEntryId
[WBXML] O Folder1
[WBXML] O </FolderHierarchy:ServerEntryId>
[WBXML] O FolderHierarchy:ParentId
[WBXML] O Trash
[WBXML] O </FolderHierarchy:ParentId>
[WBXML] O FolderHierarchy:DisplayName
[WBXML] O Folder1
[WBXML] O </FolderHierarchy:DisplayName>
[WBXML] O FolderHierarchy:Type
[WBXML] O 12
[WBXML] O </FolderHierarchy:Type>
[WBXML] O </FolderHierarchy:Update>
[WBXML] O </FolderHierarchy:Changes>// diffstate.php: DiffState::getDiffTo(‘Array’)
[0] => Array ( [id] => INBOX [type] => change ) [1] => Array ( [id] => Folder1 [type] => change ) [2] => Array ( [id] => Trash [type] => change )
[WBXML] O </FolderHierarchy:FolderSync>
[WBXML] WBXML-OUT: AwFqAAAHVkwDMQABUgN7YTIzNDMzN2QtYzA4MS00ZjliLTg1OTUtY2Y3ODg4Y2IzY2M3fTUAAU5XAzEAAVFIA0ZvbGRlcjEAAUkDVHJhc2gAAUcDRm9sZGVyMQABSgMxMgABAQEB
[WBXML] WBXML-IN : AwFqAAAHVlIDe2EyMzQzMzdkLWMwODEtNGY5Yi04NTk1LWNmNzg4OGNiM2NjN300AAEB[WBXML] O Ping:Ping
[WBXML] O Ping:Status
[WBXML] O 3
[WBXML] O </Ping:Status>
[WBXML] O </Ping:Ping>[WBXML] I Ping:Ping
[WBXML] I Ping:LifeTime
[WBXML] I 470
[WBXML] I </Ping:LifeTime>
[WBXML] I Ping:Folders
[WBXML] I Ping:Folder
[WBXML] I Ping:ServerEntryId
[WBXML] I INBOX
[WBXML] I </Ping:ServerEntryId>
[WBXML] I Ping:FolderType
[WBXML] I Email
[WBXML] I </Ping:FolderType>
[WBXML] I </Ping:Folder>
[WBXML] I </Ping:Folders>
[WBXML] I </Ping:Ping>[DEBUG] BackendIMAP->getImapIdFromFolderId(‘Folder1’) = Trash/Folder1
[DEBUG] BackendIMAP->getFolderIdFromImapId(‘Trash’) = Trash
[DEBUG] BackendIMAP->convertImapId(‘Trash’) = Trash
[DEBUG] BackendIMAP->GetFolder(‘Folder1’): ‘SyncFolder (
(S) serverid => Folder1
(S) parentid => Trash
(S) displayname => Folder1
(S) type => 12
(S) Store => null
(S) NoBackendFolder => null
(S) BackendId => null
(S) Flags => null
(S) TypeReal => null
unsetVars(Array) size: 0
supportsPrivateStripping => false
flags => false
content => null
)’
[DEBUG] ChangesMemoryWrapper->ImportFolderChange(): Change for folder ‘Folder1’ will not be sent as modification is not relevant.// diffstate.php: DiffState::getDiffTo(‘Array’)
[0] => Array ( [id] => INBOX [type] => change ) [1] => Array ( [id] => Folder1 [type] => change ) [2] => Array ( [id] => Trash [type] => change )
Please, someone can help me?