Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F117884684
kolab_storage_config.php
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Authored By
Unknown
Size
30 KB
Referenced Files
None
Subscribers
None
kolab_storage_config.php
View Options
<?php
/**
* Kolab storage class providing access to configuration objects on a Kolab server.
*
* @version @package_version@
* @author Thomas Bruederli <bruederli@kolabsys.com>
* @author Aleksander Machniak <machniak@kolabsys.com>
*
* Copyright (C) 2012-2014, Kolab Systems AG <contact@kolabsys.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
class
kolab_storage_config
{
const
FOLDER_TYPE
=
'configuration'
;
const
MAX_RELATIONS
=
499
;
// should be less than kolab_storage_cache::MAX_RECORDS
/**
* Singleton instace of kolab_storage_config
*
* @var kolab_storage_config
*/
static
protected
$instance
;
private
$folders
;
private
$default
;
private
$enabled
;
private
$tags
;
/**
* This implements the 'singleton' design pattern
*
* @return kolab_storage_config The one and only instance
*/
static
function
get_instance
()
{
if
(!
self
::
$instance
)
{
self
::
$instance
=
new
kolab_storage_config
();
}
return
self
::
$instance
;
}
/**
* Private constructor (finds default configuration folder as a config source)
*/
private
function
_init
()
{
if
(
$this
->
enabled
!==
null
)
{
return
$this
->
enabled
;
}
// get all configuration folders
$this
->
folders
=
kolab_storage
::
get_folders
(
self
::
FOLDER_TYPE
,
false
);
foreach
(
$this
->
folders
as
$folder
)
{
if
(
$folder
->
default
)
{
$this
->
default
=
$folder
;
break
;
}
}
// if no folder is set as default, choose the first one
if
(!
$this
->
default
)
{
$this
->
default
=
reset
(
$this
->
folders
);
}
// attempt to create a default folder if it does not exist
if
(!
$this
->
default
)
{
$folder_name
=
'Configuration'
;
$folder_type
=
self
::
FOLDER_TYPE
.
'.default'
;
if
(
kolab_storage
::
folder_create
(
$folder_name
,
$folder_type
,
true
))
{
$this
->
default
=
new
kolab_storage_folder
(
$folder_name
,
$folder_type
);
}
}
// check if configuration folder exist
return
$this
->
enabled
=
$this
->
default
&&
$this
->
default
->
name
;
}
/**
* Check wether any configuration storage (folder) exists
*
* @return bool
*/
public
function
is_enabled
()
{
return
$this
->
_init
();
}
/**
* Get configuration objects
*
* @param array $filter Search filter
* @param bool $default Enable to get objects only from default folder
* @param int $limit Max. number of records (per-folder)
*
* @return array List of objects
*/
public
function
get_objects
(
$filter
=
array
(),
$default
=
false
,
$limit
=
0
)
{
$list
=
array
();
if
(!
$this
->
is_enabled
())
{
return
$list
;
}
foreach
(
$this
->
folders
as
$folder
)
{
// we only want to read from default folder
if
(
$default
&&
!
$folder
->
default
)
{
continue
;
}
// for better performance it's good to assume max. number of records
if
(
$limit
)
{
$folder
->
set_order_and_limit
(
null
,
$limit
);
}
foreach
(
$folder
->
select
(
$filter
)
as
$object
)
{
unset
(
$object
[
'_formatobj'
]);
$list
[]
=
$object
;
}
}
return
$list
;
}
/**
* Get configuration object
*
* @param string $uid Object UID
* @param bool $default Enable to get objects only from default folder
*
* @return array Object data
*/
public
function
get_object
(
$uid
,
$default
=
false
)
{
if
(!
$this
->
is_enabled
())
{
return
;
}
foreach
(
$this
->
folders
as
$folder
)
{
// we only want to read from default folder
if
(
$default
&&
!
$folder
->
default
)
{
continue
;
}
if
(
$object
=
$folder
->
get_object
(
$uid
))
{
return
$object
;
}
}
}
/**
* Create/update configuration object
*
* @param array $object Object data
* @param string $type Object type
*
* @return bool True on success, False on failure
*/
public
function
save
(&
$object
,
$type
)
{
if
(!
$this
->
is_enabled
())
{
return
false
;
}
$folder
=
$this
->
find_folder
(
$object
);
if
(
$type
)
{
$object
[
'type'
]
=
$type
;
}
$status
=
$folder
->
save
(
$object
,
self
::
FOLDER_TYPE
.
'.'
.
$object
[
'type'
],
$object
[
'uid'
]);
// on success, update cached tags list
if
(
$status
&&
$object
[
'category'
]
==
'tag'
&&
is_array
(
$this
->
tags
))
{
$found
=
false
;
unset
(
$object
[
'_formatobj'
]);
// we don't need it anymore
foreach
(
$this
->
tags
as
$idx
=>
$tag
)
{
if
(
$tag
[
'uid'
]
==
$object
[
'uid'
])
{
$found
=
true
;
$this
->
tags
[
$idx
]
=
$object
;
}
}
if
(!
$found
)
{
$this
->
tags
[]
=
$object
;
}
}
return
!
empty
(
$status
);
}
/**
* Remove configuration object
*
* @param string|array $object Object array or its UID
*
* @return bool True on success, False on failure
*/
public
function
delete
(
$object
)
{
if
(!
$this
->
is_enabled
())
{
return
false
;
}
// fetch the object to find folder
if
(!
is_array
(
$object
))
{
$object
=
$this
->
get_object
(
$object
);
}
if
(!
$object
)
{
return
false
;
}
$folder
=
$this
->
find_folder
(
$object
);
$status
=
$folder
->
delete
(
$object
);
// on success, update cached tags list
if
(
$status
&&
is_array
(
$this
->
tags
))
{
foreach
(
$this
->
tags
as
$idx
=>
$tag
)
{
if
(
$tag
[
'uid'
]
==
$uid
)
{
unset
(
$this
->
tags
[
$idx
]);
break
;
}
}
}
return
$status
;
}
/**
* Find folder
*/
public
function
find_folder
(
$object
=
array
())
{
if
(!
$this
->
is_enabled
())
{
return
;
}
// find folder object
if
(
$object
[
'_mailbox'
])
{
foreach
(
$this
->
folders
as
$folder
)
{
if
(
$folder
->
name
==
$object
[
'_mailbox'
])
{
break
;
}
}
}
else
{
$folder
=
$this
->
default
;
}
return
$folder
;
}
/**
* Builds relation member URI
*
* @param string|array Object UUID or Message folder, UID, Search headers (Message-Id, Date)
*
* @return string $url Member URI
*/
public
static
function
build_member_url
(
$params
)
{
// param is object UUID
if
(
is_string
(
$params
)
&&
!
empty
(
$params
))
{
return
'urn:uuid:'
.
$params
;
}
if
(
empty
(
$params
)
||
!
strlen
(
$params
[
'folder'
]))
{
return
null
;
}
$rcube
=
rcube
::
get_instance
();
$storage
=
$rcube
->
get_storage
();
list
(
$username
,
$domain
)
=
explode
(
'@'
,
$rcube
->
get_user_name
());
if
(
strlen
(
$domain
))
{
$domain
=
'@'
.
$domain
;
}
// modify folder spec. according to namespace
$folder
=
$params
[
'folder'
];
$ns
=
$storage
->
folder_namespace
(
$folder
);
if
(
$ns
==
'shared'
)
{
// Note: this assumes there's only one shared namespace root
if
(
$ns
=
$storage
->
get_namespace
(
'shared'
))
{
if
(
$prefix
=
$ns
[
0
][
0
])
{
$folder
=
substr
(
$folder
,
strlen
(
$prefix
));
}
}
}
else
{
if
(
$ns
==
'other'
)
{
// Note: this assumes there's only one other users namespace root
if
(
$ns
=
$storage
->
get_namespace
(
'other'
))
{
if
(
$prefix
=
$ns
[
0
][
0
])
{
list
(
$otheruser
,
$path
)
=
explode
(
'/'
,
substr
(
$folder
,
strlen
(
$prefix
)),
2
);
$folder
=
'user/'
.
$otheruser
.
$domain
.
'/'
.
$path
;
}
}
}
else
{
$folder
=
'user/'
.
$username
.
$domain
.
'/'
.
$folder
;
}
}
$folder
=
implode
(
'/'
,
array_map
(
'rawurlencode'
,
explode
(
'/'
,
$folder
)));
// build URI
$url
=
'imap:///'
.
$folder
;
// UID is optional here because sometimes we want
// to build just a member uri prefix
if
(
$params
[
'uid'
])
{
$url
.=
'/'
.
$params
[
'uid'
];
}
unset
(
$params
[
'folder'
]);
unset
(
$params
[
'uid'
]);
if
(!
empty
(
$params
))
{
$url
.=
'?'
.
http_build_query
(
$params
,
''
,
'&'
);
}
return
$url
;
}
/**
* Parses relation member string
*
* @param string $url Member URI
*
* @return array Message folder, UID, Search headers (Message-Id, Date)
*/
public
static
function
parse_member_url
(
$url
)
{
// Look for IMAP URI:
// imap:///(user/username@domain|shared)/<folder>/<UID>?<search_params>
if
(
strpos
(
$url
,
'imap:///'
)
===
0
)
{
$rcube
=
rcube
::
get_instance
();
$storage
=
$rcube
->
get_storage
();
// parse_url does not work with imap:/// prefix
$url
=
parse_url
(
substr
(
$url
,
8
));
$path
=
explode
(
'/'
,
$url
[
'path'
]);
parse_str
(
$url
[
'query'
],
$params
);
$uid
=
array_pop
(
$path
);
$ns
=
array_shift
(
$path
);
$path
=
array_map
(
'rawurldecode'
,
$path
);
// resolve folder name
if
(
$ns
==
'user'
)
{
$username
=
array_shift
(
$path
);
$folder
=
implode
(
'/'
,
$path
);
if
(
$username
!=
$rcube
->
get_user_name
())
{
list
(
$user
,
$domain
)
=
explode
(
'@'
,
$username
);
// Note: this assumes there's only one other users namespace root
if
(
$ns
=
$storage
->
get_namespace
(
'other'
))
{
if
(
$prefix
=
$ns
[
0
][
0
])
{
$folder
=
$prefix
.
$user
.
'/'
.
$folder
;
}
}
}
else
if
(!
strlen
(
$folder
))
{
$folder
=
'INBOX'
;
}
}
else
{
$folder
=
$ns
.
'/'
.
implode
(
'/'
,
$path
);
// Note: this assumes there's only one shared namespace root
if
(
$ns
=
$storage
->
get_namespace
(
'shared'
))
{
if
(
$prefix
=
$ns
[
0
][
0
])
{
$folder
=
$prefix
.
$folder
;
}
}
}
return
array
(
'folder'
=>
$folder
,
'uid'
=>
$uid
,
'params'
=>
$params
,
);
}
return
false
;
}
/**
* Build array of member URIs from set of messages
*
* @param string $folder Folder name
* @param array $messages Array of rcube_message objects
*
* @return array List of members (IMAP URIs)
*/
public
static
function
build_members
(
$folder
,
$messages
)
{
$members
=
array
();
foreach
((
array
)
$messages
as
$msg
)
{
$params
=
array
(
'folder'
=>
$folder
,
'uid'
=>
$msg
->
uid
,
);
// add search parameters:
// we don't want to build "invalid" searches e.g. that
// will return false positives (more or wrong messages)
if
((
$messageid
=
$msg
->
get
(
'message-id'
,
false
))
&&
(
$date
=
$msg
->
get
(
'date'
,
false
)))
{
$params
[
'message-id'
]
=
$messageid
;
$params
[
'date'
]
=
$date
;
if
(
$subject
=
$msg
->
get
(
'subject'
,
false
))
{
$params
[
'subject'
]
=
substr
(
$subject
,
0
,
256
);
}
}
$members
[]
=
self
::
build_member_url
(
$params
);
}
return
$members
;
}
/**
* Resolve/validate/update members (which are IMAP URIs) of relation object.
*
* @param array $tag Tag object
* @param bool $force Force members list update
*
* @return array Folder/UIDs list
*/
public
static
function
resolve_members
(&
$tag
,
$force
=
true
)
{
$result
=
array
();
foreach
((
array
)
$tag
[
'members'
]
as
$member
)
{
// IMAP URI members
if
(
$url
=
self
::
parse_member_url
(
$member
))
{
$folder
=
$url
[
'folder'
];
if
(!
$force
)
{
$result
[
$folder
][]
=
$url
[
'uid'
];
}
else
{
$result
[
$folder
][
'uid'
][]
=
$url
[
'uid'
];
$result
[
$folder
][
'params'
][]
=
$url
[
'params'
];
$result
[
$folder
][
'member'
][]
=
$member
;
}
}
}
if
(
empty
(
$result
)
||
!
$force
)
{
return
$result
;
}
$rcube
=
rcube
::
get_instance
();
$storage
=
$rcube
->
get_storage
();
$search
=
array
();
$missing
=
array
();
// first we search messages by Folder+UID
foreach
(
$result
as
$folder
=>
$data
)
{
// @FIXME: maybe better use index() which is cached?
// @TODO: consider skip_deleted option
$index
=
$storage
->
search_once
(
$folder
,
'UID '
.
rcube_imap_generic
::
compressMessageSet
(
$data
[
'uid'
]));
$uids
=
$index
->
get
();
// messages that were not found need to be searched by search parameters
$not_found
=
array_diff
(
$data
[
'uid'
],
$uids
);
if
(!
empty
(
$not_found
))
{
foreach
(
$not_found
as
$uid
)
{
$idx
=
array_search
(
$uid
,
$data
[
'uid'
]);
if
(
$p
=
$data
[
'params'
][
$idx
])
{
$search
[]
=
$p
;
}
$missing
[]
=
$result
[
$folder
][
'member'
][
$idx
];
unset
(
$result
[
$folder
][
'uid'
][
$idx
]);
unset
(
$result
[
$folder
][
'params'
][
$idx
]);
unset
(
$result
[
$folder
][
'member'
][
$idx
]);
}
}
$result
[
$folder
]
=
$uids
;
}
// search in all subscribed mail folders using search parameters
if
(!
empty
(
$search
))
{
// remove not found members from the members list
$tag
[
'members'
]
=
array_diff
(
$tag
[
'members'
],
$missing
);
// get subscribed folders
$folders
=
$storage
->
list_folders_subscribed
(
''
,
'*'
,
'mail'
,
null
,
true
);
// @TODO: do this search in chunks (for e.g. 10 messages)?
$search_str
=
''
;
foreach
(
$search
as
$p
)
{
$search_params
=
array
();
foreach
(
$p
as
$key
=>
$val
)
{
$key
=
strtoupper
(
$key
);
// don't search by subject, we don't want false-positives
if
(
$key
!=
'SUBJECT'
)
{
$search_params
[]
=
'HEADER '
.
$key
.
' '
.
rcube_imap_generic
::
escape
(
$val
);
}
}
$search_str
.=
' ('
.
implode
(
' '
,
$search_params
)
.
')'
;
}
$search_str
=
trim
(
str_repeat
(
' OR'
,
count
(
$search
)-
1
)
.
$search_str
);
// search
$search
=
$storage
->
search_once
(
$folders
,
$search_str
);
// handle search result
$folders
=
(
array
)
$search
->
get_parameters
(
'MAILBOX'
);
foreach
(
$folders
as
$folder
)
{
$set
=
$search
->
get_set
(
$folder
);
$uids
=
$set
->
get
();
if
(!
empty
(
$uids
))
{
$msgs
=
$storage
->
fetch_headers
(
$folder
,
$uids
,
false
);
$members
=
self
::
build_members
(
$folder
,
$msgs
);
// merge new members into the tag members list
$tag
[
'members'
]
=
array_merge
(
$tag
[
'members'
],
$members
);
// add UIDs into the result
$result
[
$folder
]
=
array_unique
(
array_merge
((
array
)
$result
[
$folder
],
$uids
));
}
}
// update tag object with new members list
$tag
[
'members'
]
=
array_unique
(
$tag
[
'members'
]);
kolab_storage_config
::
get_instance
()->
save
(
$tag
,
'relation'
,
false
);
}
return
$result
;
}
/**
* Assign tags to kolab objects
*
* @param array $records List of kolab objects
* @param bool $no_return Don't return anything
*
* @return array List of tags
*/
public
function
apply_tags
(&
$records
,
$no_return
=
false
)
{
if
(
empty
(
$records
)
&&
$no_return
)
{
return
;
}
// first convert categories into tags
foreach
(
$records
as
$i
=>
$rec
)
{
if
(!
empty
(
$rec
[
'categories'
]))
{
$folder
=
new
kolab_storage_folder
(
$rec
[
'_mailbox'
]);
if
(
$object
=
$folder
->
get_object
(
$rec
[
'uid'
]))
{
$tags
=
$rec
[
'categories'
];
unset
(
$object
[
'categories'
]);
unset
(
$records
[
$i
][
'categories'
]);
$this
->
save_tags
(
$rec
[
'uid'
],
$tags
);
$folder
->
save
(
$object
,
$rec
[
'_type'
],
$rec
[
'uid'
]);
}
}
}
$tags
=
array
();
// assign tags to objects
foreach
(
$this
->
get_tags
()
as
$tag
)
{
foreach
(
$records
as
$idx
=>
$rec
)
{
$uid
=
self
::
build_member_url
(
$rec
[
'uid'
]);
if
(
in_array
(
$uid
,
(
array
)
$tag
[
'members'
]))
{
$records
[
$idx
][
'tags'
][]
=
$tag
[
'name'
];
}
}
$tags
[]
=
$tag
[
'name'
];
}
$tags
=
$no_return
?
null
:
array_unique
(
$tags
);
return
$tags
;
}
/**
* Assign links (relations) to kolab objects
*
* @param array $records List of kolab objects
*/
public
function
apply_links
(&
$records
)
{
$links
=
array
();
$uids
=
array
();
$ids
=
array
();
$limit
=
25
;
// get list of object UIDs and UIRs map
foreach
(
$records
as
$i
=>
$rec
)
{
$uids
[]
=
$rec
[
'uid'
];
// there can be many objects with the same uid (recurring events)
$ids
[
self
::
build_member_url
(
$rec
[
'uid'
])][]
=
$i
;
$records
[
$i
][
'links'
]
=
array
();
}
if
(!
empty
(
$uids
))
{
$uids
=
array_unique
(
$uids
);
}
// The whole story here is to not do SELECT for every object.
// We'll build one SELECT for many (limit above) objects at once
while
(!
empty
(
$uids
))
{
$chunk
=
array_splice
(
$uids
,
0
,
$limit
);
$chunk
=
array_map
(
function
(
$v
)
{
return
array
(
'member'
,
'='
,
$v
);
},
$chunk
);
$filter
=
array
(
array
(
'type'
,
'='
,
'relation'
),
array
(
'category'
,
'='
,
'generic'
),
array
(
$chunk
,
'OR'
),
);
$relations
=
$this
->
get_objects
(
$filter
,
true
,
self
::
MAX_RELATIONS
);
foreach
(
$relations
as
$relation
)
{
$links
[
$relation
[
'uid'
]]
=
$relation
;
}
}
if
(
empty
(
$links
))
{
return
;
}
// assign links of related messages
foreach
(
$links
as
$relation
)
{
// make relation members up-to-date
kolab_storage_config
::
resolve_members
(
$relation
);
$members
=
array
();
foreach
((
array
)
$relation
[
'members'
]
as
$member
)
{
if
(
strpos
(
$member
,
'imap://'
)
===
0
)
{
$members
[
$member
]
=
$member
;
}
}
$members
=
array_values
(
$members
);
// assign links to objects
foreach
((
array
)
$relation
[
'members'
]
as
$member
)
{
if
((
$id
=
$ids
[
$member
])
!==
null
)
{
foreach
(
$id
as
$i
)
{
$records
[
$i
][
'links'
]
=
array_unique
(
array_merge
(
$records
[
$i
][
'links'
],
$members
));
}
}
}
}
}
/**
* Update object tags
*
* @param string $uid Kolab object UID
* @param array $tags List of tag names
*/
public
function
save_tags
(
$uid
,
$tags
)
{
$url
=
self
::
build_member_url
(
$uid
);
$relations
=
$this
->
get_tags
();
foreach
(
$relations
as
$idx
=>
$relation
)
{
$selected
=
!
empty
(
$tags
)
&&
in_array
(
$relation
[
'name'
],
$tags
);
$found
=
!
empty
(
$relation
[
'members'
])
&&
in_array
(
$url
,
$relation
[
'members'
]);
$update
=
false
;
// remove member from the relation
if
(
$found
&&
!
$selected
)
{
$relation
[
'members'
]
=
array_diff
(
$relation
[
'members'
],
(
array
)
$url
);
$update
=
true
;
}
// add member to the relation
else
if
(!
$found
&&
$selected
)
{
$relation
[
'members'
][]
=
$url
;
$update
=
true
;
}
if
(
$update
)
{
$this
->
save
(
$relation
,
'relation'
);
}
if
(
$selected
)
{
$tags
=
array_diff
(
$tags
,
array
(
$relation
[
'name'
]));
}
}
// create new relations
if
(!
empty
(
$tags
))
{
foreach
(
$tags
as
$tag
)
{
$relation
=
array
(
'name'
=>
$tag
,
'members'
=>
(
array
)
$url
,
'category'
=>
'tag'
,
);
$this
->
save
(
$relation
,
'relation'
);
}
}
}
/**
* Get tags (all or referring to specified object)
*
* @param string $member Optional object UID or mail message-id
*
* @return array List of Relation objects
*/
public
function
get_tags
(
$member
=
'*'
)
{
if
(!
isset
(
$this
->
tags
))
{
$default
=
true
;
$filter
=
array
(
array
(
'type'
,
'='
,
'relation'
),
array
(
'category'
,
'='
,
'tag'
)
);
// use faster method
if
(
$member
&&
$member
!=
'*'
)
{
$filter
[]
=
array
(
'member'
,
'='
,
$member
);
$tags
=
$this
->
get_objects
(
$filter
,
$default
,
self
::
MAX_RELATIONS
);
}
else
{
$this
->
tags
=
$tags
=
$this
->
get_objects
(
$filter
,
$default
,
self
::
MAX_RELATIONS
);
}
}
else
{
$tags
=
$this
->
tags
;
}
if
(
$member
===
'*'
)
{
return
$tags
;
}
$result
=
array
();
if
(
$member
[
0
]
==
'<'
)
{
$search_msg
=
urlencode
(
$member
);
}
else
{
$search_uid
=
self
::
build_member_url
(
$member
);
}
foreach
(
$tags
as
$tag
)
{
if
(
$search_uid
&&
in_array
(
$search_uid
,
(
array
)
$tag
[
'members'
]))
{
$result
[]
=
$tag
;
}
else
if
(
$search_msg
)
{
foreach
(
$tag
[
'members'
]
as
$m
)
{
if
(
strpos
(
$m
,
$search_msg
)
!==
false
)
{
$result
[]
=
$tag
;
break
;
}
}
}
}
return
$result
;
}
/**
* Find objects linked with the given groupware object through a relation
*
* @param string Object UUID
*
* @return array List of related URIs
*/
public
function
get_object_links
(
$uid
)
{
$links
=
array
();
$object_uri
=
self
::
build_member_url
(
$uid
);
foreach
(
$this
->
get_relations_for_member
(
$uid
)
as
$relation
)
{
if
(
in_array
(
$object_uri
,
(
array
)
$relation
[
'members'
]))
{
// make relation members up-to-date
kolab_storage_config
::
resolve_members
(
$relation
);
foreach
(
$relation
[
'members'
]
as
$member
)
{
if
(
$member
!=
$object_uri
)
{
$links
[]
=
$member
;
}
}
}
}
return
array_unique
(
$links
);
}
/**
* Save relations of an object.
* Note, that we already support only one-to-one relations.
* So, all relations to the object that are not provided in $links
* argument will be removed.
*
* @param string $uid Object UUID
* @param array $links List of related-object URIs
*
* @return bool True on success, False on failure
*/
public
function
save_object_links
(
$uid
,
$links
)
{
$object_uri
=
self
::
build_member_url
(
$uid
);
$relations
=
$this
->
get_relations_for_member
(
$uid
);
$done
=
false
;
foreach
(
$relations
as
$relation
)
{
// make relation members up-to-date
kolab_storage_config
::
resolve_members
(
$relation
);
// remove and add links
$members
=
array
(
$object_uri
);
$members
=
array_unique
(
array_merge
(
$members
,
$links
));
// remove relation if no other members remain
if
(
count
(
$members
)
<=
1
)
{
$done
=
$this
->
delete
(
$relation
);
}
// update relation object if members changed
else
if
(
count
(
array_diff
(
$members
,
$relation
[
'members'
]))
||
count
(
array_diff
(
$relation
[
'members'
],
$members
)))
{
$relation
[
'members'
]
=
$members
;
$done
=
$this
->
save
(
$relation
,
'relation'
);
$links
=
array
();
}
// no changes, we're happy
else
{
$done
=
true
;
$links
=
array
();
}
}
// create a new relation
if
(!
$done
&&
!
empty
(
$links
))
{
$relation
=
array
(
'members'
=>
array_merge
(
$links
,
array
(
$object_uri
)),
'category'
=>
'generic'
,
);
$done
=
$this
->
save
(
$relation
,
'relation'
);
}
return
$done
;
}
/**
* Find relation objects referring to specified note
*/
public
function
get_relations_for_member
(
$uid
,
$reltype
=
'generic'
)
{
$default
=
true
;
$filter
=
array
(
array
(
'type'
,
'='
,
'relation'
),
array
(
'category'
,
'='
,
$reltype
),
array
(
'member'
,
'='
,
$uid
),
);
return
$this
->
get_objects
(
$filter
,
$default
,
self
::
MAX_RELATIONS
);
}
/**
* Find kolab objects assigned to specified e-mail message
*
* @param rcube_message $message E-mail message
* @param string $folder Folder name
* @param string $type Result objects type
*
* @return array List of kolab objects
*/
public
function
get_message_relations
(
$message
,
$folder
,
$type
)
{
static
$_cache
=
array
();
$result
=
array
();
$uids
=
array
();
$default
=
true
;
$uri
=
self
::
get_message_uri
(
$message
,
$folder
);
$filter
=
array
(
array
(
'type'
,
'='
,
'relation'
),
array
(
'category'
,
'='
,
'generic'
),
);
// query by message-id
$member_id
=
$message
->
get
(
'message-id'
,
false
);
if
(
empty
(
$member_id
))
{
// derive message identifier from URI
$member_id
=
md5
(
$uri
);
}
$filter
[]
=
array
(
'member'
,
'='
,
$member_id
);
if
(!
isset
(
$_cache
[
$uri
]))
{
// get UIDs of related groupware objects
foreach
(
$this
->
get_objects
(
$filter
,
$default
)
as
$relation
)
{
// we don't need to update members if the URI is found
if
(!
in_array
(
$uri
,
$relation
[
'members'
]))
{
// update members...
$messages
=
kolab_storage_config
::
resolve_members
(
$relation
);
// ...and check again
if
(
empty
(
$messages
[
$folder
])
||
!
in_array
(
$message
->
uid
,
$messages
[
$folder
]))
{
continue
;
}
}
// find groupware object UID(s)
foreach
(
$relation
[
'members'
]
as
$member
)
{
if
(
strpos
(
$member
,
'urn:uuid:'
)
===
0
)
{
$uids
[]
=
substr
(
$member
,
9
);
}
}
}
// remember this lookup
$_cache
[
$uri
]
=
$uids
;
}
else
{
$uids
=
$_cache
[
$uri
];
}
// get kolab objects of specified type
if
(!
empty
(
$uids
))
{
$query
=
array
(
array
(
'uid'
,
'='
,
array_unique
(
$uids
)));
$result
=
kolab_storage
::
select
(
$query
,
$type
,
count
(
$uids
));
}
return
$result
;
}
/**
* Build a URI representing the given message reference
*/
public
static
function
get_message_uri
(
$headers
,
$folder
)
{
$params
=
array
(
'folder'
=>
$headers
->
folder
?:
$folder
,
'uid'
=>
$headers
->
uid
,
);
if
((
$messageid
=
$headers
->
get
(
'message-id'
,
false
))
&&
(
$date
=
$headers
->
get
(
'date'
,
false
)))
{
$params
[
'message-id'
]
=
$messageid
;
$params
[
'date'
]
=
$date
;
if
(
$subject
=
$headers
->
get
(
'subject'
))
{
$params
[
'subject'
]
=
$subject
;
}
}
return
self
::
build_member_url
(
$params
);
}
/**
* Resolve the email message reference from the given URI
*/
public
static
function
get_message_reference
(
$uri
,
$rel
=
null
)
{
if
(
$linkref
=
self
::
parse_member_url
(
$uri
))
{
$linkref
[
'subject'
]
=
$linkref
[
'params'
][
'subject'
];
$linkref
[
'uri'
]
=
$uri
;
$rcmail
=
rcube
::
get_instance
();
if
(
method_exists
(
$rcmail
,
'url'
))
{
$linkref
[
'mailurl'
]
=
$rcmail
->
url
(
array
(
'task'
=>
'mail'
,
'action'
=>
'show'
,
'mbox'
=>
$linkref
[
'folder'
],
'uid'
=>
$linkref
[
'uid'
],
'rel'
=>
$rel
,
));
}
unset
(
$linkref
[
'params'
]);
}
return
$linkref
;
}
}
File Metadata
Details
Attached
Mime Type
text/x-php
Expires
Mon, Apr 6, 1:36 AM (2 d, 10 h ago)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
a6/f6/505fee94be23ccf37c3c8a29eb8c
Default Alt Text
kolab_storage_config.php (30 KB)
Attached To
Mode
rRPK roundcubemail-plugins-kolab
Attached
Detach File
Event Timeline