Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F117882292
SourceIMAP.php
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Authored By
Unknown
Size
10 KB
Referenced Files
None
Subscribers
None
SourceIMAP.php
View Options
<?php
/**
* This file is part of the Kolab Server Free/Busy Service
*
* @author Thomas Bruederli <bruederli@kolabsys.com>
*
* Copyright (C) 2013, 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/>.
*/
namespace
Kolab\FreeBusy
;
use
Kolab\Config
;
use
Sabre\VObject
;
use
Sabre\VObject\Component\VCalendar
;
use
Sabre\VObject\FreeBusyGenerator
;
use
Sabre\VObject\ParseException
;
// configure env for Roundcube framework
define
(
'RCUBE_INSTALL_PATH'
,
KOLAB_FREEBUSY_ROOT
.
'/'
);
define
(
'RCUBE_CONFIG_DIR'
,
KOLAB_FREEBUSY_ROOT
.
'/config/'
);
define
(
'RCUBE_PLUGINS_DIR'
,
KOLAB_FREEBUSY_ROOT
.
'/lib/plugins/'
);
/**
* Implementation of a Free/Busy data source reading from IMAP
* (not yet implemented!)
*/
class
SourceIMAP
extends
Source
{
private
$folders
=
array
();
public
function
__construct
(
$config
)
{
parent
::
__construct
(
$config
+
array
(
'mail_attributes'
=>
'mail'
));
// load the Roundcube framework with its autoloader
require_once
KOLAB_FREEBUSY_ROOT
.
'/lib/Roundcube/bootstrap.php'
;
$rcube
=
\rcube
::
get_instance
(
\rcube
::
INIT_WITH_DB
|
\rcube
::
INIT_WITH_PLUGINS
);
// Load plugins
$rcube
->
plugins
->
init
(
$rcube
);
$rcube
->
plugins
->
load_plugins
(
array
(),
array
(
'libkolab'
,
'libcalendaring'
));
}
/**
* @see Source::getFreeBusyData()
*/
public
function
getFreeBusyData
(
$user
,
$extended
)
{
$log
=
Logger
::
get
(
'imap'
,
intval
(
$this
->
config
[
'loglevel'
]));
$config
=
$this
->
getUserConfig
(
$user
);
parse_str
(
strval
(
$config
[
'query'
]),
$param
);
$config
+=
$param
;
// log this...
$log
->
addInfo
(
"Fetching data for "
,
$config
);
// caching is enabled
if
(!
empty
(
$config
[
'cacheto'
]))
{
// check for cached data
if
(
$cached
=
$this
->
getCached
(
$config
))
{
$log
->
addInfo
(
"Deliver cached data from "
.
$config
[
'cacheto'
]);
return
$cached
;
}
// touch cache file to avoid multiple requests generating the same data
if
(
file_exists
(
$config
[
'cacheto'
]))
{
touch
(
$config
[
'cacheto'
]);
}
else
{
file_put_contents
(
$config
[
'cacheto'
],
Utils
::
dummyVFreebusy
(
$user
[
'mail'
]));
$tempfile
=
$config
[
'cacheto'
];
}
}
// compose a list of user email addresses
$user_email
=
array
();
foreach
(
Config
::
convert
(
$this
->
config
[
'mail_attributes'
],
Config
::
ARR
)
as
$key
)
{
if
(!
empty
(
$user
[
$key
]))
{
$user_email
=
array_merge
(
$user_email
,
(
array
)
$user
[
$key
]);
}
}
// synchronize with IMAP and read Kolab event objects
if
(
$imap
=
$this
->
imap_login
(
$config
))
{
// target folder is specified in source URI
if
(
$config
[
'path'
]
&&
$config
[
'path'
]
!=
'/'
)
{
$folders
=
array
(
\kolab_storage
::
get_folder
(
substr
(
$config
[
'path'
],
1
)));
$read_all
=
true
;
}
else
{
// list all folders of type 'event'
$folders
=
\kolab_storage
::
get_folders
(
'event'
,
false
);
$read_all
=
false
;
}
// make \libvcalendar class available
\libcalendaring
::
get_ical
();
$utc
=
new
\DateTimezone
(
'UTC'
);
$dtstart
=
Utils
::
periodStartDT
();
$dtend
=
Utils
::
periodEndDT
();
$calendar
=
VObject\Component
::
create
(
'VCALENDAR'
);
$seen
=
array
();
$log
->
addInfo
(
"Getting events from IMAP in range"
,
array
(
$dtstart
->
format
(
'c'
),
$dtend
->
format
(
'c'
)));
$query
=
array
(
array
(
'dtstart'
,
'<='
,
$dtend
),
array
(
'dtend'
,
'>='
,
$dtstart
));
foreach
(
$folders
as
$folder
)
{
$count
=
0
;
$log
->
debug
(
'Reading Kolab folder: '
.
$folder
->
name
,
$folder
->
get_folder_info
());
// skip other user's shared calendars
if
(!
$read_all
&&
$folder
->
get_namespace
()
==
'other'
)
{
continue
;
}
// set ACL (temporarily)
if
(
$config
[
'acl'
])
{
$folder
->
_old_acl
=
$folder
->
get_myrights
();
$imap
->
set_acl
(
$folder
->
name
,
$config
[
'user'
],
$config
[
'acl'
]);
}
foreach
(
$folder
->
select
(
$query
)
as
$event
)
{
//$log->debug('Processing event', $event);
if
(
$event
[
'cancelled'
])
{
continue
;
}
// only consider shared namespace events if user is a confirmed participant (or organizer)
if
(!
$read_all
&&
$folder
->
get_namespace
()
==
'shared'
)
{
$participant
=
false
;
if
(
is_array
(
$event
[
'organizer'
])
&&
!
empty
(
$event
[
'organizer'
][
'email'
]))
{
$participant
=
in_array
(
$event
[
'organizer'
][
'email'
],
$user_email
);
}
else
if
(
is_array
(
$event
[
'attendees'
]))
{
foreach
(
$event
[
'attendees'
]
as
$attendee
)
{
if
(
in_array
(
$attendee
[
'email'
],
$user_email
))
{
if
(
$attendee
[
'status'
]
==
'ACCEPTED'
)
{
$participant
=
true
;
break
;
}
else
if
(
$attendee
[
'status'
]
==
'TENTATIVE'
)
{
$event
[
'free_busy'
]
=
'tentative'
;
$participant
=
true
;
break
;
}
}
}
}
if
(!
$participant
)
{
$log
->
debug
(
'Skip shared event'
,
array
(
$event
[
'uid'
],
$event
[
'title'
]));
continue
;
}
}
// skip declined events
else
if
(
is_array
(
$event
[
'attendees'
]))
{
foreach
(
$event
[
'attendees'
]
as
$attendee
)
{
if
(
in_array
(
$attendee
[
'email'
],
$user_email
))
{
if
(
$attendee
[
'status'
]
==
'DECLINED'
)
{
$log
->
debug
(
'Skip declined event'
,
array
(
$event
[
'uid'
],
$event
[
'title'
]));
continue
2
;
}
}
}
}
// translate all-day dates into absolute UTC times
// FIXME: use server timezone?
if
(
$event
[
'allday'
])
{
$utc
=
new
\DateTimeZone
(
'UTC'
);
if
(!
empty
(
$event
[
'start'
]))
{
$event
[
'start'
]->
setTimeZone
(
$utc
);
$event
[
'start'
]->
setTime
(
0
,
0
,
0
);
}
if
(!
empty
(
$event
[
'end'
]))
{
$event
[
'end'
]->
setTimeZone
(
$utc
);
$event
[
'end'
]->
setTime
(
23
,
59
,
59
);
}
}
// avoid duplicate entries
$key
=
$event
[
'start'
]->
format
(
'c'
)
.
'/'
.
$event
[
'end'
]->
format
(
'c'
);
if
(
$seen
[
$key
]++)
{
$log
->
debug
(
'Skipping duplicate event at '
.
$key
,
array
(
$event
[
'uid'
],
$event
[
'title'
]));
continue
;
}
// copied from libvcalendar::_to_ical()
$ve
=
VObject\Component
::
create
(
'VEVENT'
);
$ve
->
UID
=
$event
[
'uid'
];
if
(!
empty
(
$event
[
'start'
]))
$ve
->
add
(
\libvcalendar
::
datetime_prop
(
'DTSTART'
,
$event
[
'start'
],
false
,
false
));
if
(!
empty
(
$event
[
'end'
]))
$ve
->
add
(
\libvcalendar
::
datetime_prop
(
'DTEND'
,
$event
[
'end'
],
false
,
false
));
if
(!
empty
(
$event
[
'free_busy'
]))
$ve
->
add
(
'TRANSP'
,
$event
[
'free_busy'
]
==
'free'
?
'TRANSPARENT'
:
'OPAQUE'
);
if
(
$event
[
'free_busy'
]
==
'tentative'
)
$ve
->
add
(
'STATUS'
,
'TENTATIVE'
);
else
if
(!
empty
(
$event
[
'status'
]))
$ve
->
add
(
'STATUS'
,
$event
[
'status'
]);
if
(
$event
[
'recurrence'
])
{
if
(
$exdates
=
$event
[
'recurrence'
][
'EXDATE'
])
unset
(
$event
[
'recurrence'
][
'EXDATE'
]);
if
(
$rdates
=
$event
[
'recurrence'
][
'RDATE'
])
unset
(
$event
[
'recurrence'
][
'RDATE'
]);
if
(
$event
[
'recurrence'
][
'FREQ'
])
$ve
->
add
(
'RRULE'
,
\libcalendaring
::
to_rrule
(
$event
[
'recurrence'
]));
// add EXDATEs each one per line (for Thunderbird Lightning)
if
(
$exdates
)
{
foreach
(
$exdates
as
$ex
)
{
if
(
$ex
instanceof
\DateTime
)
{
$exd
=
clone
$event
[
'start'
];
$exd
->
setDate
(
$ex
->
format
(
'Y'
),
$ex
->
format
(
'n'
),
$ex
->
format
(
'j'
));
$exd
->
setTimeZone
(
$utc
);
$ve
->
add
(
new
VObject\Property
(
'EXDATE'
,
$exd
->
format
(
'Ymd
\\
THis
\\
Z'
)));
}
}
}
// add RDATEs
if
(!
empty
(
$rdates
))
{
$sample
=
\libvcalendar
::
datetime_prop
(
'RDATE'
,
$rdates
[
0
]);
$rdprop
=
new
VObject\Property\MultiDateTime
(
'RDATE'
,
null
);
$rdprop
->
setDateTimes
(
$rdates
,
$sample
->
getDateType
());
$ve
->
add
(
$rdprop
);
}
}
// append to vcalendar container
$calendar
->
add
(
$ve
);
$count
++;
$log
->
debug
(
"Adding event for processing:
\n
"
.
$ve
->
serialize
());
}
$log
->
addInfo
(
"Added $count events from folder"
.
$folder
->
name
);
}
$this
->
imap_disconnect
(
$imap
,
$config
,
$folders
);
// feed the calendar object into the free/busy generator
// we must specify a start and end date, because recurring events are expanded. nice!
$fbgen
=
new
FreeBusyGenerator
(
$dtstart
,
$dtend
,
$calendar
);
// get the freebusy report
$freebusy
=
$fbgen
->
getResult
();
$freebusy
->
PRODID
=
Utils
::
PRODID
;
$freebusy
->
METHOD
=
'PUBLISH'
;
$freebusy
->
VFREEBUSY
->
UID
=
date
(
'YmdHi'
)
.
'-'
.
substr
(
md5
(
$user_email
[
0
]),
0
,
16
);
$freebusy
->
VFREEBUSY
->
ORGANIZER
=
'mailto:'
.
$user_email
[
0
];
// serialize to VCALENDAR format
return
$freebusy
->
serialize
();
}
// remove (temporary) cache file again
else
if
(
$tempfile
)
{
unlink
(
$tempfile
);
}
return
false
;
}
/**
* Helper method to establish connection to the configured IMAP backend
*/
private
function
imap_login
(
$config
)
{
$rcube
=
\rcube
::
get_instance
();
$imap
=
$rcube
->
get_storage
();
$host
=
$config
[
'host'
];
$port
=
$config
[
'port'
]
?:
(
$config
[
'scheme'
]
==
'imaps'
?
993
:
143
);
$ssl
=
$config
[
'scheme'
]
==
'imaps'
||
$port
==
993
;
// enable proxy authentication
if
(!
empty
(
$config
[
'proxy_auth'
]))
{
$imap
->
set_options
(
array
(
'auth_cid'
=>
$config
[
'proxy_auth'
],
'auth_pw'
=>
$config
[
'pass'
]));
}
// authenticate user in IMAP
if
(!
$imap
->
connect
(
$host
,
$config
[
'user'
],
$config
[
'pass'
],
$port
,
$ssl
))
{
Logger
::
get
(
'imap'
)->
addWarning
(
"Failed to connect to IMAP server: "
.
$imap
->
get_error_code
(),
$config
);
return
false
;
}
// fake user object to rcube framework
$rcube
->
set_user
(
new
\rcube_user
(
'0'
,
array
(
'username'
=>
$config
[
'user'
])));
return
$imap
;
}
/**
* Cleanup and close IMAP connection
*/
private
function
imap_disconnect
(
$imap
,
$config
,
$folders
)
{
// reset ACL
if
(
$config
[
'acl'
]
&&
!
empty
(
$folders
))
{
foreach
(
$folders
as
$folder
)
{
$imap
->
set_acl
(
$folder
->
name
,
$config
[
'user'
],
$folder
->
_old_acl
);
}
}
$imap
->
close
();
}
}
File Metadata
Details
Attached
Mime Type
text/x-php
Expires
Mon, Apr 6, 12:28 AM (6 d, 23 h ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
18831707
Default Alt Text
SourceIMAP.php (10 KB)
Attached To
Mode
rF freebusy
Attached
Detach File
Event Timeline