mirror of
https://github.com/YunoHost-Apps/z-push_ynh.git
synced 2024-09-03 18:05:58 +02:00
Latest sources from https://github.com/fmbiete/Z-Push-contrib
This commit is contained in:
parent
13782dadb5
commit
34b3fcdf3d
246 changed files with 8091 additions and 5801 deletions
|
@ -4,21 +4,19 @@ Installing Z-Push
|
|||
Requirements
|
||||
------------
|
||||
|
||||
Z-Push 2 runs only on PHP 5.1 or later
|
||||
Z-Push 2 runs only on PHP 5.3 or later
|
||||
A PEAR dependency as in previous versions does not exist in Z-Push 2.
|
||||
|
||||
The PHP version requirement is met in these distributions and versions (or later).
|
||||
|
||||
Debian 4.0 (etch)
|
||||
Ubuntu 8.04 (hardy heron)
|
||||
RHEL/CentOS 5.5
|
||||
Fedora 5 (bordeaux)
|
||||
OpenSuse 10.1
|
||||
Slackware 12.0
|
||||
Gentoo 2006.1
|
||||
FreeBSD 6.1
|
||||
OpenBSD 4.0
|
||||
Mandriva 2007
|
||||
Debian 6.0 (squeeze)
|
||||
Ubuntu 10.04 (LTS lucid)
|
||||
RHEL/CentOS 6 (You can use SCL for newer version without overwriting system files: https://www.softwarecollections.org)
|
||||
Fedora 12 (constantine)
|
||||
OpenSuse 11.2
|
||||
Slackware 13.37
|
||||
FreeBSD 7.4
|
||||
OpenBSD 5.0
|
||||
|
||||
If your distribution is not listed here, you can check which PHP version
|
||||
is default for it at http://distrowatch.com/.
|
||||
|
@ -34,22 +32,26 @@ additional php packages are required. These provide SOAP support, access to
|
|||
process control and shared memory.
|
||||
|
||||
These packages vary in names between the distributions.
|
||||
- Generally install the packages: php-cli php-soap
|
||||
- Generally install the packages: php-cli php-soap
|
||||
- On Suse (SLES & OpenSuse) install the packages: php53 php53-soap php53-pcntl php53-sysvshm php53-sysvsem php53-posix
|
||||
- On RHEL based systems install the package: php-cli php-soap php-process
|
||||
In order to install these packages you need to add an extra channel subscription
|
||||
from the RHEL Server Optional channel.
|
||||
|
||||
|
||||
Be aware that each backend can have their own requirements. Take a look to the
|
||||
REQUIREMENTS file inside its folder for more information.
|
||||
|
||||
|
||||
How to install
|
||||
--------------
|
||||
|
||||
To install Z-Push, simply untar the z-push archive, e.g. with:
|
||||
tar -xzvf z-push-[version]-{buildnr}.tar.gz
|
||||
|
||||
|
||||
The tar contains a folder which has the following structure:
|
||||
z-push-[version]-{buildnr}
|
||||
|
||||
|
||||
The contents of this folder should be copied to /usr/share/z-push.
|
||||
In a case that /usr/share/z-push does not exist yet, create it with:
|
||||
mkdir -p /usr/share/z-push
|
||||
|
@ -70,7 +72,7 @@ your apache process or make the directories world writeable:
|
|||
|
||||
chmod 755 /var/lib/z-push /var/log/z-push
|
||||
chown apache:apache /var/lib/z-push /var/log/z-push
|
||||
|
||||
|
||||
For the default webserver user please refer to your distribution's manual.
|
||||
|
||||
Now, you must configure Apache to redirect the URL
|
||||
|
@ -122,7 +124,7 @@ FileStateMachine (which is default). In order to make this possible,
|
|||
you either need to disable the php-safe-mode in php.ini or .htaccess with
|
||||
php_admin_flag safe_mode off
|
||||
or configure it accordingly, so Z-Push is allowed to write to the
|
||||
log and state directories.
|
||||
log and state directories.
|
||||
|
||||
After doing this, you should be able to synchronize with your mobile device.
|
||||
|
||||
|
@ -217,7 +219,7 @@ property. It should be mapped to 0x3A220102 in ldap.propmap.cfg
|
|||
(0x3A220102 = userCertificate). Make sure it looks like this in LDAP:
|
||||
|
||||
userCertificate;binary
|
||||
MIIFGjCCBAKgAwIBAgIQbRnqpxlPa…
|
||||
MIIFGjCCBAKgAwIBAgIQbRnqpxlPa…
|
||||
|
||||
*Important*
|
||||
It is strongly recommended to use MS AD or LDAP to manage certificates.
|
||||
|
@ -273,11 +275,11 @@ synchronisation.
|
|||
*every* user on the system. You can set a different log level for particular
|
||||
users by adding them comma separated to $specialLogUsers in the config.php
|
||||
e.g. $specialLogUsers = array("user1", "user2", "user3");
|
||||
|
||||
*NOTE* Be aware that if you are using LOGLEVEL_DEBUG and LOGLEVEL_WBXML
|
||||
|
||||
*NOTE* Be aware that if you are using LOGLEVEL_DEBUG and LOGLEVEL_WBXML
|
||||
Z-Push will be quite talkative, so it is advisable to use log-rotate
|
||||
on the log file.
|
||||
|
||||
|
||||
*Repeated incorrect password messages*
|
||||
If a password contains characters which are encoded differently in ISO-8859-1
|
||||
and Windows-1252 encodings (e.g. "§") the login might fail with Z-Push but
|
||||
|
|
4
sources/NOTES
Normal file
4
sources/NOTES
Normal file
|
@ -0,0 +1,4 @@
|
|||
Run composer to update autoinclude
|
||||
==================================
|
||||
curl -sS https://getcomposer.org/installer | php
|
||||
php composer.phar dump-autoload -o
|
|
@ -1,6 +1,8 @@
|
|||
Z-Push-contrib
|
||||
==============
|
||||
|
||||
[](https://gitter.im/fmbiete/Z-Push-contrib?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
|
||||
This is a Z-Push fork with changes that I will try to put into the contrib branch, so they can get into the official Z-Push
|
||||
|
||||
IMPORTANT:
|
||||
|
@ -31,9 +33,9 @@ You can find some configuration guidelines in the Wiki https://github.com/fmbiet
|
|||
|
||||
Requisites
|
||||
==========
|
||||
- PHP 5.5 (5.3 should also work, 5.4 it's fine, but 5.5 is better)
|
||||
- PHP 5.x (5.3 it's the minimum supported) using PHP-FPM or MOD_PHP
|
||||
- HHVM 3.6 or newer, instead of PHP
|
||||
- NGINX or APACHE
|
||||
- PHP-FPM or MOD_PHP
|
||||
|
||||
Configuration
|
||||
=============
|
||||
|
|
|
@ -1,208 +1,177 @@
|
|||
Z-Push AutoDiscover manual
|
||||
--------------------------
|
||||
This manual gives an introduction to the Z-Push AutoDiscover service, discusses
|
||||
technical details and explains the installation.
|
||||
|
||||
Introduction
|
||||
------------
|
||||
AutoDiscover is the service used to simplify the configuration of collaboration
|
||||
accounts for clients, especially for mobile phones.
|
||||
While in the past the user was required to enter the server name, user name and
|
||||
password manually into his mobile phone in order to connect, with AutoDiscover
|
||||
the user is only required to fill in his email address and the password.
|
||||
AutoDiscover will try several methods to reach the correct server automatically.
|
||||
|
||||
|
||||
How does it work?
|
||||
-----------------
|
||||
When speaking about AutoDiscover, this includes two distinct realms:
|
||||
- AutoDiscover is a specification which defines the steps a client should take
|
||||
in order to contact a service to request additional data.
|
||||
- The AutoDiscover service is piece of software which accepts requests from the
|
||||
clients, authenticates them, requests some additional data from the
|
||||
collaboration server and sends this data back to the client.
|
||||
The specification suggests several ways for client to contact the responsible
|
||||
server to receive additional information. Tests have shown, that basically all
|
||||
mobile phones tested support only the most basic ways. These are sufficient for
|
||||
almost all types of scenarios and are the ones implemented by Z-Push AutoDiscover.
|
||||
Please refer to the Mobile Compatibility List (http://z-push.sf.net/compatibility)
|
||||
for an overview of supported and tested devices.
|
||||
The used email address is the key for the process. The client splits it up into
|
||||
the local and domain part (before and after the @-sign). The client then tries
|
||||
to connect to this domain in order to get in contact with the AutoDiscover
|
||||
service. The local part of the email address is used as "login" to the
|
||||
AutoDiscover service. There is also an option, to use the full email address as
|
||||
login name (see "Configuration" section below for details).
|
||||
|
||||
|
||||
---------------
|
||||
| Client |
|
||||
| e.g. mobile |
|
||||
---------------
|
||||
/ \
|
||||
1. Searches for / \ 2. Data access
|
||||
information / \
|
||||
/ \
|
||||
V V
|
||||
---------------- --------------
|
||||
| AutoDiscover | redirects to | Z-Push |
|
||||
| | --------------------> | ActiveSync |
|
||||
---------------- --------------
|
||||
\ /
|
||||
Authen- \ / Synchronizes
|
||||
ticates \ /
|
||||
via Z-Push \ /
|
||||
Backend V V
|
||||
-----------------
|
||||
| Collaboration |
|
||||
| Platform |
|
||||
-----------------
|
||||
|
||||
Requirements
|
||||
------------
|
||||
As described in the previous chapter, the local part of the email address or
|
||||
the email address is used in order to log in.
|
||||
Your configuration requires that this type of login is possible:
|
||||
- either the user name is used to login and must be used in the email address
|
||||
entered on the mobile, or
|
||||
- the entire email address is used to login.
|
||||
|
||||
Which option is used has to be configured in the AutoDiscover configuration and
|
||||
in the underlying platform (e.g. ZCP (hosting mode)).
|
||||
Most companies use the user name as local part of the email by default. From the
|
||||
AutoDiscover point of view, it is not required that user is able to receive
|
||||
emails at the used email address. It is recommended allowing that in order not
|
||||
to confuse end users.
|
||||
|
||||
AutoDiscover also requires a valid SSL certificate to work as expected. A very
|
||||
little percentage of mobiles support self-signed certificates (showing a
|
||||
pop-up alerting the user). Most mobiles silently ignore self-signed certificates
|
||||
and just declare the AutoDiscover process as failed in such cases.
|
||||
If AutoDiscover fails, the user is generally redirected to the
|
||||
"manual configuration" of the client.
|
||||
|
||||
If you do not plan to acquire an official certificate, you will probably not be
|
||||
able to use the AutoDiscover service.
|
||||
Depending on your setup, it could be necessary to add new DNS entries for your
|
||||
mail domain.
|
||||
|
||||
|
||||
Domain setup
|
||||
------------
|
||||
There are two general ways the AutoDiscover process can be configured:
|
||||
1. Directly with "yourdomain.com" website ("www.yourdomain.com" will most
|
||||
probably not work)
|
||||
2. With the sub-domain "autodiscover.yourdomain.com"
|
||||
In both cases, an official SSL certificate is required. If you already have a
|
||||
certificate for your domain, the webserver answering for that domain could be
|
||||
reconfigured to allow AutoDiscover requests as well. In the case that you do
|
||||
not have direct access to this type of configuration (e.g. hosting provider),
|
||||
it's recommended to acquire a dedicated certificate for
|
||||
"autodiscover.yourdomain.com". Please note, that this sub-domain can NOT be
|
||||
renamed. In general, "wildcard" certificates can be used, as long they are
|
||||
valid for the required domain.
|
||||
|
||||
|
||||
Software requirements
|
||||
---------------------
|
||||
Like Z-Push, AutoDiscover is written in PHP, where PHP 5.1 or newer is required.
|
||||
Please consult the Z-Push INSTALL file for further information about PHP versions.
|
||||
If only AutoDiscover is to be executed on a host, the Z-Push PHP dependencies do
|
||||
NOT need to be installed.
|
||||
AutoDiscover has one direct dependency, the php-xml parser library.
|
||||
|
||||
These packages vary in names between the distributions.
|
||||
- Generally install the packages: php-xml
|
||||
- On Suse (SLES & OpenSuse) install the packages: php53-xml
|
||||
- On RHEL based systems install the package: php-xml
|
||||
|
||||
|
||||
Installation
|
||||
------------
|
||||
AutoDiscover is part of the Z-Push package and uses some of the functionality
|
||||
available in Z-Push.
|
||||
It is possible to install AutoDiscover on the same host as Z-Push, or to
|
||||
install them on different hosts.
|
||||
|
||||
Currently, independently from the setup, it's recommended to extract the entire
|
||||
z-push tarball and configure the services as required.
|
||||
Please follow the install instructions from the Z-Push INSTALL file (section
|
||||
"How to install") to copy the files to your server.
|
||||
If you do not want to setup Z-Push on the host, do not add the "Alias" for
|
||||
ActiveSync.
|
||||
|
||||
To setup the SSL certificate, please refer to one of the many setup guides
|
||||
available on the internet, like that one:
|
||||
http://www.apache.com/resources/how-to-setup-an-ssl-certificate-on-apache/
|
||||
|
||||
The mobiles requests these URLs (where "yourdomain.com" corresponds to the
|
||||
domain part of the email used in the client):
|
||||
https://yourdomain.com/Autodiscover/Autodiscover.xml and/or
|
||||
https://autodiscover.yourdomain.com/Autodiscover/Autodiscover.xml
|
||||
|
||||
Add the following line to the apache site configuration file.
|
||||
AliasMatch (?i)/Autodiscover/Autodiscover.xml "/usr/share/z-push/autodiscover/autodiscover.php"
|
||||
|
||||
This line assumes that Z-Push is installed in /usr/share/z-push. If the path
|
||||
is different, please adjust it accordingly.
|
||||
|
||||
Note: some mobiles use different casings, like "AutoDiscover" in the URL. The
|
||||
above statement is valid for these as well.
|
||||
|
||||
Please restart Apache afterwards.
|
||||
|
||||
|
||||
Configuration
|
||||
-------------
|
||||
There are several parameters in the configuration file, which allow to customize
|
||||
the behaviour of the AutoDiscover Service.
|
||||
The configuration, generally is located in the z-push/autodiscover directory and
|
||||
is called "config.php".
|
||||
|
||||
The parameters:
|
||||
BASE_PATH This property specifies where the AutoDiscover files are
|
||||
located. Normally there is no need to adjust this parameter.
|
||||
SERVERURL This is the full URL where the Z-Push server is available.
|
||||
You should adjust it to the domain/server where Z-Push is
|
||||
installed.
|
||||
|
||||
USE_FULLEMAIL_FOR_LOGIN If this is set to "true", AutoDiscover will attempt to
|
||||
login on the collaboration server with the full email
|
||||
address sent by the client. If disabled (default), the
|
||||
local part of the email address is used.
|
||||
|
||||
LOGFILEDIR The directory where logfiles are created.
|
||||
|
||||
LOGFILE The default AutoDiscover log file.
|
||||
|
||||
LOGERRORFILE The default AutoDiscover error log file.
|
||||
|
||||
LOGLEVEL The loglevel, set it to WBXML to see the data received
|
||||
and sent from/to clients.
|
||||
|
||||
LOGAUTHFAIL Set to true, to explicitly log failed login attempts.
|
||||
|
||||
BACKEND_PROVIDER The backend to be used. If empty (default) the code
|
||||
will auto detect which backend to use.
|
||||
|
||||
Please note: the desired backend also needs to be configured, in the
|
||||
"backends/<backend>/config.php" file.
|
||||
|
||||
|
||||
Test installation
|
||||
-----------------
|
||||
If everything is correct, accessing with a browser the URL for your setup, you
|
||||
should see:
|
||||
1. a pop-up asking for your username + password. Always use the email
|
||||
address which you would also enter on the mobile (independently from
|
||||
the configuration).
|
||||
2. if the authentication was successful, you will see a Z-Push informational
|
||||
page (like when accessing the Z-Push location).
|
||||
|
||||
Note: The same test can also be performed in the mobiles web browser to check
|
||||
if the access works correctly from the mobile network.
|
||||
|
||||
If the authentication fails, please check the configuration options of AutoDiscover.
|
||||
Also check the logfiles for possible failures.
|
||||
|
||||
If the manual method works, try setting up your mobile phone! :)
|
||||
Z-Push AutoDiscover manual
|
||||
--------------------------
|
||||
This manual gives an introduction to the Z-Push AutoDiscover service, discusses
|
||||
technical details and explains the installation.
|
||||
|
||||
Introduction
|
||||
------------
|
||||
AutoDiscover is the service used to simplify the configuration of collaboration
|
||||
accounts for clients, especially for mobile phones.
|
||||
While in the past the user was required to enter the server name, user name and
|
||||
password manually into his mobile phone in order to connect, with AutoDiscover
|
||||
the user is only required to fill in his email address and the password.
|
||||
AutoDiscover will try several methods to reach the correct server automatically.
|
||||
|
||||
|
||||
How does it work?
|
||||
-----------------
|
||||
When speaking about AutoDiscover, this includes two distinct realms:
|
||||
- AutoDiscover is a specification which defines the steps a client should take
|
||||
in order to contact a service to request additional data.
|
||||
- The AutoDiscover service is piece of software which accepts requests from the
|
||||
clients, authenticates them, requests some additional data from the
|
||||
collaboration server and sends this data back to the client.
|
||||
The specification suggests several ways for client to contact the responsible
|
||||
server to receive additional information. Tests have shown, that basically all
|
||||
mobile phones tested support only the most basic ways. These are sufficient for
|
||||
almost all types of scenarios and are the ones implemented by Z-Push AutoDiscover.
|
||||
Please refer to the Mobile Compatibility List (http://z-push.sf.net/compatibility)
|
||||
for an overview of supported and tested devices.
|
||||
The used email address is the key for the process. The client splits it up into
|
||||
the local and domain part (before and after the @-sign). The client then tries
|
||||
to connect to this domain in order to get in contact with the AutoDiscover
|
||||
service. The local part of the email address is used as "login" to the
|
||||
AutoDiscover service. There is also an option, to use the full email address as
|
||||
login name (see "Configuration" section below for details).
|
||||
|
||||
|
||||
---------------
|
||||
| Client |
|
||||
| e.g. mobile |
|
||||
---------------
|
||||
/ \
|
||||
1. Searches for / \ 2. Data access
|
||||
information / \
|
||||
/ \
|
||||
V V
|
||||
---------------- --------------
|
||||
| AutoDiscover | redirects to | Z-Push |
|
||||
| | --------------------> | ActiveSync |
|
||||
---------------- --------------
|
||||
\ /
|
||||
Authen- \ / Synchronizes
|
||||
ticates \ /
|
||||
via Z-Push \ /
|
||||
Backend V V
|
||||
-----------------
|
||||
| Collaboration |
|
||||
| Platform |
|
||||
-----------------
|
||||
|
||||
Requirements
|
||||
------------
|
||||
As described in the previous chapter, the local part of the email address or
|
||||
the email address is used in order to log in.
|
||||
Your configuration requires that this type of login is possible:
|
||||
- either the user name is used to login and must be used in the email address
|
||||
entered on the mobile, or
|
||||
- the entire email address is used to login.
|
||||
|
||||
Which option is used has to be configured in the AutoDiscover configuration and
|
||||
in the underlying platform (e.g. ZCP (hosting mode)).
|
||||
Most companies use the user name as local part of the email by default. From the
|
||||
AutoDiscover point of view, it is not required that user is able to receive
|
||||
emails at the used email address. It is recommended allowing that in order not
|
||||
to confuse end users.
|
||||
|
||||
AutoDiscover also requires a valid SSL certificate to work as expected. A very
|
||||
little percentage of mobiles support self-signed certificates (showing a
|
||||
pop-up alerting the user). Most mobiles silently ignore self-signed certificates
|
||||
and just declare the AutoDiscover process as failed in such cases.
|
||||
If AutoDiscover fails, the user is generally redirected to the
|
||||
"manual configuration" of the client.
|
||||
|
||||
If you do not plan to acquire an official certificate, you will probably not be
|
||||
able to use the AutoDiscover service.
|
||||
Depending on your setup, it could be necessary to add new DNS entries for your
|
||||
mail domain.
|
||||
|
||||
|
||||
Domain setup
|
||||
------------
|
||||
There are two general ways the AutoDiscover process can be configured:
|
||||
1. Directly with "yourdomain.com" website ("www.yourdomain.com" will most
|
||||
probably not work)
|
||||
2. With the sub-domain "autodiscover.yourdomain.com"
|
||||
In both cases, an official SSL certificate is required. If you already have a
|
||||
certificate for your domain, the webserver answering for that domain could be
|
||||
reconfigured to allow AutoDiscover requests as well. In the case that you do
|
||||
not have direct access to this type of configuration (e.g. hosting provider),
|
||||
it's recommended to acquire a dedicated certificate for
|
||||
"autodiscover.yourdomain.com". Please note, that this sub-domain can NOT be
|
||||
renamed. In general, "wildcard" certificates can be used, as long they are
|
||||
valid for the required domain.
|
||||
|
||||
|
||||
Software requirements
|
||||
---------------------
|
||||
Like Z-Push, AutoDiscover is written in PHP, where PHP 5.3 or newer is required.
|
||||
Please consult the Z-Push INSTALL file for further information about PHP versions.
|
||||
If only AutoDiscover is to be executed on a host, the Z-Push PHP dependencies do
|
||||
NOT need to be installed.
|
||||
AutoDiscover has one direct dependency, the php-xml parser library.
|
||||
|
||||
These packages vary in names between the distributions.
|
||||
- Generally install the packages: php-xml
|
||||
- On Suse (SLES & OpenSuse) install the packages: php53-xml
|
||||
- On RHEL based systems install the package: php-xml
|
||||
|
||||
|
||||
Installation
|
||||
------------
|
||||
AutoDiscover is part of the Z-Push package and uses some of the functionality
|
||||
available in Z-Push.
|
||||
It is possible to install AutoDiscover on the same host as Z-Push, or to
|
||||
install them on different hosts.
|
||||
|
||||
Currently, independently from the setup, it's recommended to extract the entire
|
||||
z-push tarball and configure the services as required.
|
||||
Please follow the install instructions from the Z-Push INSTALL file (section
|
||||
"How to install") to copy the files to your server.
|
||||
If you do not want to setup Z-Push on the host, do not add the "Alias" for
|
||||
ActiveSync.
|
||||
|
||||
To setup the SSL certificate, please refer to one of the many setup guides
|
||||
available on the internet, like that one:
|
||||
http://www.apache.com/resources/how-to-setup-an-ssl-certificate-on-apache/
|
||||
|
||||
The mobiles requests these URLs (where "yourdomain.com" corresponds to the
|
||||
domain part of the email used in the client):
|
||||
https://yourdomain.com/Autodiscover/Autodiscover.xml and/or
|
||||
https://autodiscover.yourdomain.com/Autodiscover/Autodiscover.xml
|
||||
|
||||
Add the following line to the apache site configuration file.
|
||||
AliasMatch (?i)/Autodiscover/Autodiscover.xml$ "/usr/share/z-push/autodiscover/autodiscover.php"
|
||||
|
||||
This line assumes that Z-Push is installed in /usr/share/z-push. If the path
|
||||
is different, please adjust it accordingly.
|
||||
|
||||
Note: some mobiles use different casings, like "AutoDiscover" in the URL. The
|
||||
above statement is valid for these as well.
|
||||
|
||||
Please restart Apache afterwards.
|
||||
|
||||
|
||||
Configuration
|
||||
-------------
|
||||
You don't need extra configuration for the AutoDiscover Service. It will use
|
||||
the configuration already defined for the main Z-Push Service.
|
||||
|
||||
|
||||
Test installation
|
||||
-----------------
|
||||
If everything is correct, accessing with a browser the URL for your setup, you
|
||||
should see:
|
||||
1. a pop-up asking for your username + password. Always use the email
|
||||
address which you would also enter on the mobile (independently from
|
||||
the configuration).
|
||||
2. if the authentication was successful, you will see a Z-Push informational
|
||||
page (like when accessing the Z-Push location).
|
||||
|
||||
Note: The same test can also be performed in the mobiles web browser to check
|
||||
if the access works correctly from the mobile network.
|
||||
|
||||
If the authentication fails, please check the configuration options of AutoDiscover.
|
||||
Also check the logfiles for possible failures.
|
||||
|
||||
If the manual method works, try setting up your mobile phone! :)
|
||||
|
|
|
@ -41,19 +41,8 @@
|
|||
* Consult LICENSE file for details
|
||||
************************************************/
|
||||
|
||||
include_once('../lib/core/zpushdefs.php');
|
||||
include_once('../lib/exceptions/exceptions.php');
|
||||
include_once('../lib/utils/utils.php');
|
||||
include_once('../lib/core/zpush.php');
|
||||
include_once('../lib/core/zlog.php');
|
||||
include_once('../lib/interface/ibackend.php');
|
||||
include_once('../lib/interface/ichanges.php');
|
||||
include_once('../lib/interface/iexportchanges.php');
|
||||
include_once('../lib/interface/iimportchanges.php');
|
||||
include_once('../lib/interface/isearchprovider.php');
|
||||
include_once('../lib/interface/istatemachine.php');
|
||||
include_once('../version.php');
|
||||
include_once('config.php');
|
||||
require_once '../vendor/autoload.php';
|
||||
require_once '../config.php';
|
||||
|
||||
class ZPushAutodiscover {
|
||||
const ACCEPTABLERESPONSESCHEMA = 'http://schemas.microsoft.com/exchange/autodiscover/mobilesync/responseschema/2006';
|
||||
|
@ -120,9 +109,8 @@ class ZPushAutodiscover {
|
|||
else {
|
||||
ZLog::Write(LOGLEVEL_ERROR, sprintf("Unable to complete autodiscover incorrect request: '%s'", $ex->getMessage()));
|
||||
}
|
||||
header('HTTP/1.1 401 Unauthorized');
|
||||
header('WWW-Authenticate: Basic realm="ZPush"');
|
||||
http_response_code(401);
|
||||
header('WWW-Authenticate: Basic realm="ZPush"');
|
||||
}
|
||||
catch (ZPushException $ex) {
|
||||
ZLog::Write(LOGLEVEL_ERROR, sprintf("Unable to complete autodiscover because of ZPushException. Error: %s", $ex->getMessage()));
|
||||
|
@ -220,12 +208,13 @@ class ZPushAutodiscover {
|
|||
* @return string
|
||||
*/
|
||||
private function createResponse($email, $userFullname) {
|
||||
$server_url = 'https://' . $_SERVER['SERVER_NAME'] . '/Microsoft-Server-ActiveSync';
|
||||
$xml = file_get_contents('response.xml');
|
||||
$response = new SimpleXMLElement($xml);
|
||||
$response->Response->User->DisplayName = $userFullname;
|
||||
$response->Response->User->EMailAddress = $email;
|
||||
$response->Response->Action->Settings->Server->Url = SERVERURL;
|
||||
$response->Response->Action->Settings->Server->Name = SERVERURL;
|
||||
$response->Response->Action->Settings->Server->Url = $server_url;
|
||||
$response->Response->Action->Settings->Server->Name = $server_url;
|
||||
$response = $response->asXML();
|
||||
ZLog::Write(LOGLEVEL_WBXML, sprintf("ZPushAutodiscover->createResponse() XML response:%s%s", PHP_EOL, $response));
|
||||
return $response;
|
||||
|
@ -259,10 +248,9 @@ class ZPushAutodiscover {
|
|||
if (isset($userDetails[$attrib]) && $userDetails[$attrib]) {
|
||||
return $userDetails[$attrib];
|
||||
}
|
||||
ZLog::Write(LOGLEVEL_WARN, sprintf("The backend was not able to find attribute '%s' of the user. Fall back to the default value."));
|
||||
ZLog::Write(LOGLEVEL_WARN, sprintf("The backend was not able to find attribute '%s' of the user. Fall back to the default value.", $attrib));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ZPushAutodiscover::DoZPushAutodiscover();
|
||||
?>
|
|
@ -1,89 +0,0 @@
|
|||
<?php
|
||||
/***********************************************
|
||||
* File : config.php
|
||||
* Project : Z-Push
|
||||
* Descr : Autodiscover configuration file
|
||||
*
|
||||
* Created : 30.07.2014
|
||||
*
|
||||
* Copyright 2007 - 2014 Zarafa Deutschland GmbH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation with the following additional
|
||||
* term according to sec. 7:
|
||||
*
|
||||
* According to sec. 7 of the GNU Affero General Public License, version 3,
|
||||
* the terms of the AGPL are supplemented with the following terms:
|
||||
*
|
||||
* "Zarafa" is a registered trademark of Zarafa B.V.
|
||||
* "Z-Push" is a registered trademark of Zarafa Deutschland GmbH
|
||||
* The licensing of the Program under the AGPL does not imply a trademark license.
|
||||
* Therefore any rights, title and interest in our trademarks remain entirely with us.
|
||||
*
|
||||
* However, if you propagate an unmodified version of the Program you are
|
||||
* allowed to use the term "Z-Push" to indicate that you distribute the Program.
|
||||
* Furthermore you may use our trademarks where it is necessary to indicate
|
||||
* the intended purpose of a product or service provided you use it in accordance
|
||||
* with honest practices in industrial or commercial matters.
|
||||
* If you want to propagate modified versions of the Program under the name "Z-Push",
|
||||
* you may only do so if you have a written permission by Zarafa Deutschland GmbH
|
||||
* (to acquire a permission please contact Zarafa at trademark@zarafa.com).
|
||||
*
|
||||
* 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/>.
|
||||
*
|
||||
* Consult LICENSE file for details
|
||||
************************************************/
|
||||
|
||||
/**********************************************************************************
|
||||
* Default settings
|
||||
*/
|
||||
// Defines the base path on the server
|
||||
define('BASE_PATH', dirname($_SERVER['SCRIPT_FILENAME']). '/');
|
||||
|
||||
// The Z-Push server location for the autodiscover response
|
||||
define('SERVERURL', 'https://localhost/Microsoft-Server-ActiveSync');
|
||||
|
||||
/*
|
||||
* Whether to use the complete email address as a login name
|
||||
* (e.g. user@company.com) or the username only (user).
|
||||
* Possible values:
|
||||
* false - use the username only (default).
|
||||
* true - use the complete email address.
|
||||
*/
|
||||
define('USE_FULLEMAIL_FOR_LOGIN', false);
|
||||
|
||||
/**********************************************************************************
|
||||
* Logging settings
|
||||
* Possible LOGLEVEL and LOGUSERLEVEL values are:
|
||||
* LOGLEVEL_OFF - no logging
|
||||
* LOGLEVEL_FATAL - log only critical errors
|
||||
* LOGLEVEL_ERROR - logs events which might require corrective actions
|
||||
* LOGLEVEL_WARN - might lead to an error or require corrective actions in the future
|
||||
* LOGLEVEL_INFO - usually completed actions
|
||||
* LOGLEVEL_DEBUG - debugging information, typically only meaningful to developers
|
||||
* LOGLEVEL_WBXML - also prints the WBXML sent to/from the device
|
||||
* LOGLEVEL_DEVICEID - also prints the device id for every log entry
|
||||
* LOGLEVEL_WBXMLSTACK - also prints the contents of WBXML stack
|
||||
*
|
||||
* The verbosity increases from top to bottom. More verbose levels include less verbose
|
||||
* ones, e.g. setting to LOGLEVEL_DEBUG will also output LOGLEVEL_FATAL, LOGLEVEL_ERROR,
|
||||
* LOGLEVEL_WARN and LOGLEVEL_INFO level entries.
|
||||
*/
|
||||
define('LOGFILEDIR', '/var/log/z-push/');
|
||||
define('LOGFILE', LOGFILEDIR . 'autodiscover.log');
|
||||
define('LOGERRORFILE', LOGFILEDIR . 'autodiscover-error.log');
|
||||
define('LOGLEVEL', LOGLEVEL_INFO);
|
||||
define('LOGUSERLEVEL', LOGLEVEL);
|
||||
/**********************************************************************************
|
||||
* Backend settings
|
||||
*/
|
||||
// the backend data provider
|
||||
define('BACKEND_PROVIDER', '');
|
||||
?>
|
|
@ -46,25 +46,20 @@
|
|||
// config file
|
||||
require_once("backend/caldav/config.php");
|
||||
|
||||
include_once('lib/default/diffbackend/diffbackend.php');
|
||||
include_once('include/z_caldav.php');
|
||||
include_once('include/z_RTF.php');
|
||||
include_once('include/iCalendar.php');
|
||||
|
||||
class BackendCalDAV extends BackendDiff {
|
||||
/**
|
||||
* @var CalDAVClient
|
||||
*/
|
||||
private $_caldav;
|
||||
private $_caldav_path;
|
||||
private $_collection = array();
|
||||
private $_username;
|
||||
|
||||
private $changessinkinit;
|
||||
private $sinkdata;
|
||||
private $sinkmax;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
*/
|
||||
public function BackendCalDAV() {
|
||||
if (!function_exists("curl_init")) {
|
||||
|
@ -81,18 +76,17 @@ class BackendCalDAV extends BackendDiff {
|
|||
* @see IBackend::Logon()
|
||||
*/
|
||||
public function Logon($username, $domain, $password) {
|
||||
$this->_username = $username;
|
||||
$this->_caldav_path = str_replace('%u', $username, CALDAV_PATH);
|
||||
$this->_caldav = new CalDAVClient(CALDAV_SERVER . ":" . CALDAV_PORT . $this->_caldav_path, $username, $password);
|
||||
$options = $this->_caldav->DoOptionsRequest();
|
||||
if (isset($options["PROPFIND"])) {
|
||||
ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendCalDAV->Logon(): User '%s' is authenticated on CalDAV", $username));
|
||||
return true;
|
||||
$url = sprintf("%s://%s:%d%s", CALDAV_PROTOCOL, CALDAV_SERVER, CALDAV_PORT, $this->_caldav_path);
|
||||
$this->_caldav = new CalDAVClient($url, $username, $password);
|
||||
if ($connected = $this->_caldav->CheckConnection()) {
|
||||
ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendCalDAV->Logon(): User '%s' is authenticated on CalDAV '%s'", $username, $url));
|
||||
}
|
||||
else {
|
||||
ZLog::Write(LOGLEVEL_WARN, sprintf("BackendCalDAV->Logon(): User '%s' is not authenticated on CalDAV", $username));
|
||||
return false;
|
||||
ZLog::Write(LOGLEVEL_WARN, sprintf("BackendCalDAV->Logon(): User '%s' is not authenticated on CalDAV '%s'", $username, $url));
|
||||
}
|
||||
|
||||
return $connected;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -100,14 +94,18 @@ class BackendCalDAV extends BackendDiff {
|
|||
* @see IBackend::Logoff()
|
||||
*/
|
||||
public function Logoff() {
|
||||
ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendCalDAV->Logoff()"));
|
||||
$this->_caldav = null;
|
||||
if ($this->_caldav != null) {
|
||||
$this->_caldav->Disconnect();
|
||||
unset($this->_caldav);
|
||||
}
|
||||
|
||||
$this->SaveStorages();
|
||||
|
||||
unset($this->sinkdata);
|
||||
unset($this->sinkmax);
|
||||
|
||||
ZLog::Write(LOGLEVEL_DEBUG, "BackendCalDAV->Logoff(): disconnected from CALDAV server");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -306,15 +304,14 @@ class BackendCalDAV extends BackendDiff {
|
|||
}
|
||||
else {
|
||||
$etag = "*";
|
||||
$date = gmdate("Ymd\THis\Z");
|
||||
$random = hash("md5", microtime());
|
||||
$id = $date . "-" . $random . ".ics";
|
||||
$id = sprintf("%s-%s.ics", gmdate("Ymd\THis\Z"), hash("md5", microtime()));
|
||||
}
|
||||
|
||||
$data = $this->_ParseASToVCalendar($message, $folderid, substr($id, 0, strlen($id)-4));
|
||||
|
||||
$url = $this->_caldav_path . substr($folderid, 1) . "/" . $id;
|
||||
$etag_new = $this->_caldav->DoPUTRequest($url, $data, $etag);
|
||||
|
||||
$data = $this->_ParseASToVCalendar($message, $folderid, substr($id, 0, strlen($id) - 4));
|
||||
|
||||
$etag_new = $this->CreateUpdateCalendar($data, $url, $etag);
|
||||
|
||||
$item = array();
|
||||
$item['href'] = $id;
|
||||
|
@ -333,21 +330,6 @@ class BackendCalDAV extends BackendDiff {
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the 'star' flag of a message on disk
|
||||
*
|
||||
* @param string $folderid id of the folder
|
||||
* @param string $id id of the message
|
||||
* @param int $flags star flag of the message
|
||||
*
|
||||
* @access public
|
||||
* @return boolean status of the operation
|
||||
* @throws StatusException could throw specific SYNC_STATUS_* exceptions
|
||||
*/
|
||||
public function SetStarFlag($folderid, $id, $flags, $contentParameters) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a message from the CalDAV server.
|
||||
* @see BackendDiff::DeleteMessage()
|
||||
|
@ -356,10 +338,7 @@ class BackendCalDAV extends BackendDiff {
|
|||
ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendCalDAV->DeleteMessage('%s','%s')", $folderid, $id));
|
||||
$url = $this->_caldav_path . substr($folderid, 1) . "/" . $id;
|
||||
$http_status_code = $this->_caldav->DoDELETERequest($url);
|
||||
if ($http_status_code == "204") {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return $http_status_code == "204";
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -370,6 +349,51 @@ class BackendCalDAV extends BackendDiff {
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create or Update one event
|
||||
*
|
||||
* @access public
|
||||
* @param $data string VCALENDAR text
|
||||
* @param $url string URL for the calendar, if false a new calendar object is created
|
||||
* @param $etag string ETAG for the calendar, if '*' is a new object
|
||||
* @return array
|
||||
*/
|
||||
public function CreateUpdateCalendar($data, $url = false, $etag = "*") {
|
||||
if ($url === false) {
|
||||
$url = sprintf("%s%s/%s-%s.ics", $this->_caldav_path, CALDAV_PERSONAL, gmdate("Ymd\THis\Z"), hash("md5", microtime()));
|
||||
$etag = "*";
|
||||
}
|
||||
|
||||
return $this->_caldav->DoPUTRequest($url, $data, $etag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes one VCALENDAR
|
||||
*
|
||||
* @access public
|
||||
* @param $id string ID of the VCALENDAR
|
||||
* @return boolean
|
||||
*/
|
||||
public function DeleteCalendar($id) {
|
||||
$http_status_code = $this->_caldav->DoDELETERequest(sprintf("%s%s/%s", $this->_caldav_path, CALDAV_PERSONAL, $id));
|
||||
return $http_status_code == "204";
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds one VCALENDAR
|
||||
*
|
||||
* @access public
|
||||
* @param $uid string UID attribute
|
||||
* @return array
|
||||
*/
|
||||
public function FindCalendar($uid) {
|
||||
$filter = sprintf("<C:filter><C:comp-filter name=\"VCALENDAR\"><C:comp-filter name=\"VEVENT\"><C:prop-filter name=\"UID\"><C:text-match>%s</C:text-match></C:prop-filter></C:comp-filter></C:comp-filter></C:filter>", $uid);
|
||||
|
||||
$events = $this->_caldav->DoCalendarQuery($filter, sprintf("%s%s", $this->_caldav_path, CALDAV_PERSONAL));
|
||||
|
||||
return $events;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates which AS version is supported by the backend.
|
||||
*
|
||||
|
@ -444,57 +468,59 @@ class BackendCalDAV extends BackendDiff {
|
|||
return $notifications;
|
||||
}
|
||||
|
||||
while($stopat > time() && empty($notifications)) {
|
||||
// only check once to reduce pressure in the DAV server
|
||||
foreach ($this->sinkdata as $k => $v) {
|
||||
$changed = false;
|
||||
|
||||
foreach ($this->sinkdata as $k => $v) {
|
||||
$changed = false;
|
||||
$url = $this->_caldav_path . substr($k, 1) . "/";
|
||||
$response = $this->_caldav->GetSync($url, false, CALDAV_SUPPORTS_SYNC);
|
||||
|
||||
$url = $this->_caldav_path . substr($k, 1) . "/";
|
||||
$response = $this->_caldav->GetSync($url, false, CALDAV_SUPPORTS_SYNC);
|
||||
|
||||
if (CALDAV_SUPPORTS_SYNC) {
|
||||
if (count($response) > 0) {
|
||||
$changed = true;
|
||||
ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendCalDAV->ChangesSink - Changes detected"));
|
||||
}
|
||||
if (CALDAV_SUPPORTS_SYNC) {
|
||||
if (count($response) > 0) {
|
||||
$changed = true;
|
||||
ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendCalDAV->ChangesSink - Changes detected"));
|
||||
}
|
||||
}
|
||||
else {
|
||||
// If the numbers of events are different, we know for sure, there are changes
|
||||
if (count($response) != count($v)) {
|
||||
$changed = true;
|
||||
ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendCalDAV->ChangesSink - Changes detected"));
|
||||
}
|
||||
else {
|
||||
// If the numbers of events are different, we know for sure, there are changes
|
||||
if (count($response) != count($v)) {
|
||||
$changed = true;
|
||||
// If the numbers of events are equals, we compare the biggest date
|
||||
// FIXME: we are comparing strings no dates
|
||||
if (!isset($this->sinkmax[$k])) {
|
||||
$this->sinkmax[$k] = '';
|
||||
for ($i = 0; $i < count($v); $i++) {
|
||||
if ($v[$i]['getlastmodified'] > $this->sinkmax[$k]) {
|
||||
$this->sinkmax[$k] = $v[$i]['getlastmodified'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for ($i = 0; $i < count($response); $i++) {
|
||||
if ($response[$i]['getlastmodified'] > $this->sinkmax[$k]) {
|
||||
$changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ($changed) {
|
||||
ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendCalDAV->ChangesSink - Changes detected"));
|
||||
}
|
||||
else {
|
||||
// If the numbers of events are equals, we compare the biggest date
|
||||
// FIXME: we are comparing strings no dates
|
||||
if (!isset($this->sinkmax[$k])) {
|
||||
$this->sinkmax[$k] = '';
|
||||
for ($i = 0; $i < count($v); $i++) {
|
||||
if ($v[$i]['getlastmodified'] > $this->sinkmax[$k]) {
|
||||
$this->sinkmax[$k] = $v[$i]['getlastmodified'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for ($i = 0; $i < count($response); $i++) {
|
||||
if ($response[$i]['getlastmodified'] > $this->sinkmax[$k]) {
|
||||
$changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ($changed) {
|
||||
ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendCalDAV->ChangesSink - Changes detected"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($changed) {
|
||||
$notifications[] = $k;
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($notifications))
|
||||
sleep(5);
|
||||
if ($changed) {
|
||||
$notifications[] = $k;
|
||||
}
|
||||
}
|
||||
|
||||
// Wait to timeout
|
||||
if (empty($notifications)) {
|
||||
while ($stopat > time()) {
|
||||
sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
return $notifications;
|
||||
|
@ -508,7 +534,8 @@ class BackendCalDAV extends BackendDiff {
|
|||
* @return SyncAppointment
|
||||
*/
|
||||
private function _ParseVEventToAS($data, $contentparameters) {
|
||||
ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendCalDAV->_ParseVEventToAS(): Parsing VEvent"));
|
||||
ZLog::Write(LOGLEVEL_DEBUG, "BackendCalDAV->_ParseVEventToAS(): Parsing VEvent");
|
||||
|
||||
$truncsize = Utils::GetTruncSize($contentparameters->GetTruncation());
|
||||
$message = new SyncAppointment();
|
||||
|
||||
|
@ -700,7 +727,6 @@ class BackendCalDAV extends BackendDiff {
|
|||
$body = Utils::Utf8_truncate($body, $truncsize);
|
||||
$message->bodytruncated = 1;
|
||||
} else {
|
||||
$body = $body;
|
||||
$message->bodytruncated = 0;
|
||||
}
|
||||
$body = str_replace("\n","\r\n", str_replace("\r","",$body));
|
||||
|
@ -739,6 +765,12 @@ class BackendCalDAV extends BackendDiff {
|
|||
}
|
||||
}
|
||||
|
||||
// Workaround #127 - No organizeremail defined
|
||||
if (!isset($message->organizeremail)) {
|
||||
ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendCalDAV->_ParseVEventToSyncObject(): No organizeremail defined, using username"));
|
||||
$message->organizeremail = $this->originalUsername;
|
||||
}
|
||||
|
||||
$valarm = current($event->GetComponents("VALARM"));
|
||||
if ($valarm) {
|
||||
$properties = $valarm->GetProperties();
|
||||
|
@ -880,7 +912,7 @@ class BackendCalDAV extends BackendDiff {
|
|||
$ical = new iCalComponent();
|
||||
$ical->SetType("VCALENDAR");
|
||||
$ical->AddProperty("VERSION", "2.0");
|
||||
$ical->AddProperty("PRODID", "-//php-push//NONSGML PHP-Push Calendar//EN");
|
||||
$ical->AddProperty("PRODID", "-//z-push-contrib//NONSGML Z-Push-contrib Calendar//EN");
|
||||
$ical->AddProperty("CALSCALE", "GREGORIAN");
|
||||
|
||||
if ($folderid[0] == "C") {
|
||||
|
@ -950,9 +982,11 @@ class BackendCalDAV extends BackendDiff {
|
|||
if (isset($data->endtime)) {
|
||||
if ($data->alldayevent == 1) {
|
||||
$vevent->AddProperty("DTEND", $this->_GetDateFromUTC("Ymd", $data->endtime, $data->timezone), array("VALUE" => "DATE"));
|
||||
$vevent->AddProperty("X-MICROSOFT-CDO-ALLDAYEVENT", "TRUE");
|
||||
}
|
||||
else {
|
||||
$vevent->AddProperty("DTEND", gmdate("Ymd\THis\Z", $data->endtime));
|
||||
$vevent->AddProperty("X-MICROSOFT-CDO-ALLDAYEVENT", "FALSE");
|
||||
}
|
||||
}
|
||||
if (isset($data->recurrence)) {
|
||||
|
@ -1002,13 +1036,19 @@ class BackendCalDAV extends BackendDiff {
|
|||
switch ($data->meetingstatus) {
|
||||
case "1":
|
||||
$vevent->AddProperty("STATUS", "TENTATIVE");
|
||||
$vevent->AddProperty("X-MICROSOFT-CDO-BUSYSTATUS", "TENTATIVE");
|
||||
$vevent->AddProperty("X-MICROSOFT-DISALLOW-COUNTER", "FALSE");
|
||||
break;
|
||||
case "3":
|
||||
$vevent->AddProperty("STATUS", "CONFIRMED");
|
||||
$vevent->AddProperty("X-MICROSOFT-CDO-BUSYSTATUS", "CONFIRMED");
|
||||
$vevent->AddProperty("X-MICROSOFT-DISALLOW-COUNTER", "FALSE");
|
||||
break;
|
||||
case "5":
|
||||
case "7":
|
||||
$vevent->AddProperty("STATUS", "CANCELLED");
|
||||
$vevent->AddProperty("X-MICROSOFT-CDO-BUSYSTATUS", "CANCELLED");
|
||||
$vevent->AddProperty("X-MICROSOFT-DISALLOW-COUNTER", "TRUE");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1017,11 +1057,15 @@ class BackendCalDAV extends BackendDiff {
|
|||
//Some phones doesn't send the organizeremail, so we gotto get it somewhere else.
|
||||
//Lets use the login here ($username)
|
||||
if (!isset($data->organizeremail)) {
|
||||
$vevent->AddProperty("ORGANIZER", sprintf("MAILTO:%s", $this->_username));
|
||||
$vevent->AddProperty("ORGANIZER", sprintf("MAILTO:%s", $this->originalUsername));
|
||||
}
|
||||
foreach ($data->attendees as $att) {
|
||||
$att_str = sprintf("MAILTO:%s", $att->email);
|
||||
$vevent->AddProperty("ATTENDEE", $att_str, array("CN" => $att->name));
|
||||
if (isset($att->name)) {
|
||||
$vevent->AddProperty("ATTENDEE", sprintf("MAILTO:%s", $att->email), array("CN" => $att->name));
|
||||
}
|
||||
else {
|
||||
$vevent->AddProperty("ATTENDEE", sprintf("MAILTO:%s", $att->email));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isset($data->body)) {
|
||||
|
@ -1034,6 +1078,13 @@ class BackendCalDAV extends BackendDiff {
|
|||
$vevent->AddProperty("CATEGORIES", implode(",", $data->categories));
|
||||
}
|
||||
|
||||
// X-MICROSOFT-CDO-APPT-SEQUENCE:0
|
||||
// X-MICROSOFT-CDO-OWNERAPPTID:2113393086
|
||||
// X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY
|
||||
// X-MICROSOFT-CDO-IMPORTANCE:1
|
||||
// X-MICROSOFT-CDO-INSTTYPE:0
|
||||
|
||||
|
||||
return $vevent;
|
||||
}
|
||||
|
||||
|
@ -1461,6 +1512,4 @@ class BackendCalDAV extends BackendDiff {
|
|||
}
|
||||
return base64_encode(pack('la64vvvvvvvvla64vvvvvvvvl', 0, '', 0, 0, 0, 0, 0, 0, 0, 0, 0, '', 0, 0, 0, 0, 0, 0, 0, 0, 0));
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
}
|
|
@ -45,23 +45,23 @@
|
|||
// BackendCalDAV settings
|
||||
// ************************
|
||||
|
||||
// Server address
|
||||
define('CALDAV_SERVER', 'http://calendar.domain.com');
|
||||
// Server protocol: http or https
|
||||
define('CALDAV_PROTOCOL', 'https');
|
||||
|
||||
// Port
|
||||
define('CALDAV_PORT', '80');
|
||||
// Server name
|
||||
define('CALDAV_SERVER', 'caldavserver.domain.com');
|
||||
|
||||
// Server port
|
||||
define('CALDAV_PORT', '443');
|
||||
|
||||
// Path
|
||||
define('CALDAV_PATH', '/caldav.php/%u/');
|
||||
|
||||
// Default CalDAV folder (calendar folder/principal). This will be marked as the default calendar in the mobile
|
||||
define('CALDAV_PERSONAL', 'home');
|
||||
define('CALDAV_PERSONAL', 'PRINCIPAL');
|
||||
|
||||
// If the CalDAV server supports the sync-collection operation
|
||||
// DAViCal, SOGo and SabreDav support it
|
||||
// SabreDav version must be at least 1.9.0, otherwise set this to false
|
||||
// Setting this to false will work with most servers, but it will be slower
|
||||
define('CALDAV_SUPPORTS_SYNC', false);
|
||||
|
||||
|
||||
?>
|
||||
define('CALDAV_SUPPORTS_SYNC', false);
|
|
@ -44,14 +44,14 @@
|
|||
// config file
|
||||
require_once("backend/carddav/config.php");
|
||||
|
||||
include_once('lib/default/diffbackend/diffbackend.php');
|
||||
include_once('include/z_carddav.php');
|
||||
|
||||
class BackendCardDAV extends BackendDiff implements ISearchProvider {
|
||||
|
||||
private $domain = '';
|
||||
private $username = '';
|
||||
private $url = null;
|
||||
/**
|
||||
* @var carddav_backend
|
||||
*/
|
||||
private $server = null;
|
||||
private $default_url = null;
|
||||
private $gal_url = null;
|
||||
|
@ -131,8 +131,10 @@ class BackendCardDAV extends BackendDiff implements ISearchProvider {
|
|||
* @return boolean
|
||||
*/
|
||||
public function Logoff() {
|
||||
ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendCardDAV->Logoff()"));
|
||||
$this->server = null;
|
||||
if ($this->server != null) {
|
||||
$this->server->disconnect();
|
||||
unset($this->server);
|
||||
}
|
||||
|
||||
$this->SaveStorages();
|
||||
|
||||
|
@ -140,6 +142,8 @@ class BackendCardDAV extends BackendDiff implements ISearchProvider {
|
|||
unset($this->sinkdata);
|
||||
unset($this->addressbooks);
|
||||
|
||||
ZLog::Write(LOGLEVEL_DEBUG, "BackendCardDAV->Logoff(): disconnected from CARDDAV server");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -207,8 +211,6 @@ class BackendCardDAV extends BackendDiff implements ISearchProvider {
|
|||
public function ChangesSinkInitialize($folderid) {
|
||||
ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendCardDAV->ChangesSinkInitialize(): folderid '%s'", $folderid));
|
||||
|
||||
|
||||
|
||||
// We don't need the actual cards, we only need to get the changes since this moment
|
||||
$init_ok = true;
|
||||
foreach ($this->addressbooks as $addressbook) {
|
||||
|
@ -261,58 +263,61 @@ class BackendCardDAV extends BackendDiff implements ISearchProvider {
|
|||
return $notifications;
|
||||
}
|
||||
|
||||
while($stopat > time() && empty($notifications)) {
|
||||
foreach ($this->addressbooks as $addressbook) {
|
||||
$vcards = false;
|
||||
try {
|
||||
$this->server->set_url($addressbook);
|
||||
$vcards = $this->server->do_sync(false, false, CARDDAV_SUPPORTS_SYNC);
|
||||
}
|
||||
catch (Exception $ex) {
|
||||
ZLog::Write(LOGLEVEL_ERROR, sprintf("BackendCardDAV->ChangesSink - Error resyncing vcards: %s", $ex->getMessage()));
|
||||
}
|
||||
|
||||
if ($vcards === false) {
|
||||
ZLog::Write(LOGLEVEL_ERROR, sprintf("BackendCardDAV->ChangesSink - Error getting the changes"));
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
$xml_vcards = new SimpleXMLElement($vcards);
|
||||
|
||||
if (CARDDAV_SUPPORTS_SYNC) {
|
||||
if (count($xml_vcards->element) > 0) {
|
||||
$changed = true;
|
||||
ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendCardDAV->ChangesSink - Changes detected"));
|
||||
}
|
||||
}
|
||||
else {
|
||||
$xml_sinkdata = new SimpleXMLElement($this->sinkdata[$addressbook]);
|
||||
if (count($xml_vcards->element) != count($xml_sinkdata->element)) {
|
||||
// If the number of cards is different, we know for sure, there are changes
|
||||
$changed = true;
|
||||
ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendCardDAV->ChangesSink - Changes detected"));
|
||||
}
|
||||
else {
|
||||
// If it's the same we need to check vcard to vcard, or the original strings
|
||||
if (strcmp($this->sinkdata[$addressbook], $vcards) != 0) {
|
||||
$changed = true;
|
||||
ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendCardDAV->ChangesSink - Changes detected"));
|
||||
}
|
||||
}
|
||||
unset($xml_sinkdata);
|
||||
}
|
||||
|
||||
unset($vcards);
|
||||
unset($xml_vcards);
|
||||
}
|
||||
|
||||
if ($changed) {
|
||||
$notifications[] = $this->foldername;
|
||||
}
|
||||
// only check once to reduce pressure in the DAV server
|
||||
foreach ($this->addressbooks as $addressbook) {
|
||||
$vcards = false;
|
||||
try {
|
||||
$this->server->set_url($addressbook);
|
||||
$vcards = $this->server->do_sync(false, false, CARDDAV_SUPPORTS_SYNC);
|
||||
}
|
||||
catch (Exception $ex) {
|
||||
ZLog::Write(LOGLEVEL_ERROR, sprintf("BackendCardDAV->ChangesSink - Error resyncing vcards: %s", $ex->getMessage()));
|
||||
}
|
||||
|
||||
if (empty($notifications))
|
||||
sleep(5);
|
||||
if ($vcards === false) {
|
||||
ZLog::Write(LOGLEVEL_ERROR, sprintf("BackendCardDAV->ChangesSink - Error getting the changes"));
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
$xml_vcards = new SimpleXMLElement($vcards);
|
||||
|
||||
if (CARDDAV_SUPPORTS_SYNC) {
|
||||
if (count($xml_vcards->element) > 0) {
|
||||
$changed = true;
|
||||
ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendCardDAV->ChangesSink - Changes detected"));
|
||||
}
|
||||
}
|
||||
else {
|
||||
$xml_sinkdata = new SimpleXMLElement($this->sinkdata[$addressbook]);
|
||||
if (count($xml_vcards->element) != count($xml_sinkdata->element)) {
|
||||
// If the number of cards is different, we know for sure, there are changes
|
||||
$changed = true;
|
||||
ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendCardDAV->ChangesSink - Changes detected"));
|
||||
}
|
||||
else {
|
||||
// If it's the same we need to check vcard to vcard, or the original strings
|
||||
if (strcmp($this->sinkdata[$addressbook], $vcards) != 0) {
|
||||
$changed = true;
|
||||
ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendCardDAV->ChangesSink - Changes detected"));
|
||||
}
|
||||
}
|
||||
unset($xml_sinkdata);
|
||||
}
|
||||
|
||||
unset($vcards);
|
||||
unset($xml_vcards);
|
||||
}
|
||||
|
||||
if ($changed) {
|
||||
$notifications[] = $this->foldername;
|
||||
}
|
||||
}
|
||||
|
||||
// Wait to timeout
|
||||
if (empty($notifications)) {
|
||||
while ($stopat > time()) {
|
||||
sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
return $notifications;
|
||||
|
@ -545,7 +550,6 @@ class BackendCardDAV extends BackendDiff implements ISearchProvider {
|
|||
$message["mod"] = $this->contactsetag[$id];
|
||||
$message["id"] = $id;
|
||||
$message["flags"] = 1;
|
||||
$message["star"] = 0;
|
||||
|
||||
return $message;
|
||||
}
|
||||
|
@ -641,23 +645,6 @@ class BackendCardDAV extends BackendDiff implements ISearchProvider {
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the 'star' flag of a message on disk
|
||||
* Not implemented here
|
||||
*
|
||||
* @param string $folderid id of the folder
|
||||
* @param string $id id of the message
|
||||
* @param int $flags star flag of the message
|
||||
* @param ContentParameters $contentParameters
|
||||
*
|
||||
* @access public
|
||||
* @return boolean status of the operation
|
||||
* @throws StatusException could throw specific SYNC_STATUS_* exceptions
|
||||
*/
|
||||
public function SetStarFlag($folderid, $id, $flags, $contentParameters) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the user has requested to delete (really delete) a message
|
||||
*
|
||||
|
@ -959,7 +946,8 @@ class BackendCardDAV extends BackendDiff implements ISearchProvider {
|
|||
}
|
||||
|
||||
/**
|
||||
* Converts the vCard into SyncContact
|
||||
* Converts the vCard into SyncContact.
|
||||
* See RFC 6350 for vCard format details.
|
||||
*
|
||||
* @param string $data string with the vcard
|
||||
* @param int $truncsize truncate size requested
|
||||
|
@ -1001,45 +989,49 @@ class BackendCardDAV extends BackendDiff implements ISearchProvider {
|
|||
continue;
|
||||
|
||||
$field = trim(substr($line, 0, $pos));
|
||||
$value = trim(substr($line, $pos+1));
|
||||
$value = trim(substr($line, $pos + 1));
|
||||
|
||||
$fieldparts = preg_split('/(?<!\\\\)(\;)/i', $field, -1, PREG_SPLIT_NO_EMPTY);
|
||||
|
||||
// The base type
|
||||
$type = strtolower(array_shift($fieldparts));
|
||||
|
||||
$fieldvalue = array();
|
||||
// We do not care about visually grouping properties together, so strip groups off (see RFC 6350 § 3.3)
|
||||
if (preg_match('#^[a-z0-9\\-]+\\.(.+)$#i', $type, $matches)) {
|
||||
$type = $matches[1];
|
||||
}
|
||||
|
||||
// Parse all field values
|
||||
$fieldvalue = array();
|
||||
foreach ($fieldparts as $fieldpart) {
|
||||
if (preg_match('/([^=]+)=(.+)/', $fieldpart, $matches)) {
|
||||
if (!in_array(strtolower($matches[1]), array('value', 'type', 'encoding', 'language')))
|
||||
$fieldName = strtolower($matches[1]);
|
||||
if (!in_array($fieldName, array('value', 'type', 'encoding', 'language')))
|
||||
continue;
|
||||
if (isset($fieldvalue[strtolower($matches[1])]) && is_array($fieldvalue[strtolower($matches[1])])) {
|
||||
if (strtolower($matches[1]) == 'type') {
|
||||
$fieldvalue[strtolower($matches[1])] = array_merge($fieldvalue[strtolower($matches[1])], array_map('strtolower', preg_split('/(?<!\\\\)(\,)/i', $matches[2], -1, PREG_SPLIT_NO_EMPTY)));
|
||||
if (isset($fieldvalue[$fieldName]) && is_array($fieldvalue[$fieldName])) {
|
||||
if ($fieldName == 'type') {
|
||||
$fieldvalue[$fieldName] = array_merge($fieldvalue[$fieldName], array_map('strtolower', preg_split('/(?<!\\\\)(\,)/i', $matches[2], -1, PREG_SPLIT_NO_EMPTY)));
|
||||
} else {
|
||||
$fieldvalue[$fieldName] = array_merge($fieldvalue[$fieldName], preg_split('/(?<!\\\\)(\,)/i', $matches[2], -1, PREG_SPLIT_NO_EMPTY));
|
||||
}
|
||||
else {
|
||||
$fieldvalue[strtolower($matches[1])] = array_merge($fieldvalue[strtolower($matches[1])], preg_split('/(?<!\\\\)(\,)/i', $matches[2], -1, PREG_SPLIT_NO_EMPTY));
|
||||
} else {
|
||||
if ($fieldName == 'type') {
|
||||
$fieldvalue[$fieldName] = array_map('strtolower', preg_split('/(?<!\\\\)(\,)/i', $matches[2], -1, PREG_SPLIT_NO_EMPTY));
|
||||
} else {
|
||||
$fieldvalue[$fieldName] = preg_split('/(?<!\\\\)(\,)/i', $matches[2], -1, PREG_SPLIT_NO_EMPTY);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (strtolower($matches[1]) == 'type') {
|
||||
$fieldvalue[strtolower($matches[1])] = array_map('strtolower', preg_split('/(?<!\\\\)(\,)/i', $matches[2], -1, PREG_SPLIT_NO_EMPTY));
|
||||
}
|
||||
else {
|
||||
$fieldvalue[strtolower($matches[1])] = preg_split('/(?<!\\\\)(\,)/i', $matches[2], -1, PREG_SPLIT_NO_EMPTY);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
if (!isset($types[strtolower($fieldpart)]))
|
||||
continue;
|
||||
$fieldvalue[$types[strtolower($fieldpart)]][] = $fieldpart;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
switch ($type) {
|
||||
case 'categories':
|
||||
//case 'nickname':
|
||||
//case 'nickname':
|
||||
$val = preg_split('/(\s)*(\\\)?\,(\s)*/i', $value);
|
||||
break;
|
||||
default:
|
||||
|
@ -1061,8 +1053,7 @@ class BackendCardDAV extends BackendDiff implements ISearchProvider {
|
|||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
foreach ($val as $i => $v) {
|
||||
$val[$i] = $this->unescape($v);
|
||||
}
|
||||
|
@ -1125,6 +1116,7 @@ class BackendCardDAV extends BackendDiff implements ISearchProvider {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
//;;street;city;state;postalcode;country
|
||||
if (isset($vcard['adr'])) {
|
||||
foreach ($vcard['adr'] as $adr) {
|
||||
|
@ -1212,8 +1204,13 @@ class BackendCardDAV extends BackendDiff implements ISearchProvider {
|
|||
$message->bodysize = strlen($message->body);
|
||||
}
|
||||
}
|
||||
|
||||
// Support both ROLE and TITLE (RFC 6350 § 6.6.1 / § 6.6.2) as mapped to JobTitle
|
||||
if (!empty($vcard['role'][0]['val'][0]))
|
||||
$message->jobtitle = $vcard['role'][0]['val'][0];//$vcard['title'][0]['val'][0]
|
||||
$message->jobtitle = $vcard['role'][0]['val'][0];
|
||||
if (!empty($vcard['title'][0]['val'][0]))
|
||||
$message->jobtitle = $vcard['title'][0]['val'][0];
|
||||
|
||||
if (!empty($vcard['url'][0]['val'][0]))
|
||||
$message->webpage = $vcard['url'][0]['val'][0];
|
||||
if (!empty($vcard['categories'][0]['val']))
|
||||
|
@ -1448,5 +1445,4 @@ class BackendCardDAV extends BackendDiff implements ISearchProvider {
|
|||
return $addressbookId;
|
||||
}
|
||||
|
||||
};
|
||||
?>
|
||||
}
|
|
@ -49,9 +49,6 @@
|
|||
* Consult LICENSE file for details
|
||||
************************************************/
|
||||
|
||||
// default backend
|
||||
include_once('lib/default/backend.php');
|
||||
|
||||
//include the CombinedBackend's own config file
|
||||
require_once("backend/combined/config.php");
|
||||
require_once("backend/combined/importer.php");
|
||||
|
@ -59,11 +56,19 @@ require_once("backend/combined/exporter.php");
|
|||
|
||||
class BackendCombined extends Backend implements ISearchProvider {
|
||||
public $config;
|
||||
/**
|
||||
* @var IBackend[]
|
||||
*/
|
||||
public $backends;
|
||||
/**
|
||||
* @var IBackend
|
||||
*/
|
||||
private $activeBackend;
|
||||
private $activeBackendID;
|
||||
private $numberChangesSink;
|
||||
|
||||
private $logon_done = false;
|
||||
|
||||
/**
|
||||
* Constructor of the combined backend
|
||||
*
|
||||
|
@ -100,6 +105,8 @@ class BackendCombined extends Backend implements ISearchProvider {
|
|||
$u = $username;
|
||||
$d = $domain;
|
||||
$p = $password;
|
||||
|
||||
// Apply mapping from configuration
|
||||
if(isset($this->config['backends'][$i]['users'])){
|
||||
if(!isset($this->config['backends'][$i]['users'][$username])){
|
||||
unset($this->backends[$i]);
|
||||
|
@ -112,12 +119,23 @@ class BackendCombined extends Backend implements ISearchProvider {
|
|||
if(isset($this->config['backends'][$i]['users'][$username]['domain']))
|
||||
$d = $this->config['backends'][$i]['users'][$username]['domain'];
|
||||
}
|
||||
if($this->backends[$i]->Logon($u, $d, $p) == false){
|
||||
|
||||
// Apply username mapping from state backend
|
||||
if (isset($this->config['usemapping']) && $this->config['usemapping']) {
|
||||
$mappedUsername = ZPush::GetStateMachine()->GetMappedUsername($u, strtolower($this->config['backends'][$i]['name']));
|
||||
if ($mappedUsername !== null) {
|
||||
$u = $mappedUsername;
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->backends[$i]->Logon($u, $d, $p) == false) {
|
||||
ZLog::Write(LOGLEVEL_DEBUG, sprintf("Combined->Logon() failed on %s ", $this->config['backends'][$i]['name']));
|
||||
return false;
|
||||
}
|
||||
$this->backends[$i]->SetOriginalUsername($username);
|
||||
}
|
||||
|
||||
$this->logon_done = true;
|
||||
ZLog::Write(LOGLEVEL_DEBUG, "Combined->Logon() success");
|
||||
return true;
|
||||
}
|
||||
|
@ -167,6 +185,10 @@ class BackendCombined extends Backend implements ISearchProvider {
|
|||
* @return boolean
|
||||
*/
|
||||
public function Logoff() {
|
||||
// If no Logon in done, omit Logoff
|
||||
if (!$this->logon_done)
|
||||
return true;
|
||||
|
||||
ZLog::Write(LOGLEVEL_DEBUG, "Combined->Logoff()");
|
||||
foreach ($this->backends as $i => $b){
|
||||
$this->backends[$i]->Logoff();
|
||||
|
@ -459,27 +481,21 @@ class BackendCombined extends Backend implements ISearchProvider {
|
|||
|
||||
$notifications = array();
|
||||
if ($this->numberChangesSink == 0) {
|
||||
ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendCombined doesn't include any Sinkable backends"));
|
||||
ZLog::Write(LOGLEVEL_DEBUG, "BackendCombined doesn't include any Sinkable backends");
|
||||
} else {
|
||||
$stopat = time() + $timeout - 1;
|
||||
//we will spend 2 seconds at least in each backend that support changessink
|
||||
// why 2 seconds? because it's the minimum to ensure we run at least once the changessink
|
||||
// I think it's fairer than run for 10 continuos seconds the same backend (run backend1, run backend2, run backend1, run backend2... vs run backend1, run backend1, run backend2, run backend2)
|
||||
do {
|
||||
foreach ($this->backends as $i => $b) {
|
||||
if ($this->backends[$i]->HasChangesSink()) {
|
||||
ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendCombined->ChangesSink - Calling in '%s' with %d", get_class($b), 2));
|
||||
$time_each = $timeout / $this->numberChangesSink;
|
||||
foreach ($this->backends as $i => $b) {
|
||||
if ($this->backends[$i]->HasChangesSink()) {
|
||||
ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendCombined->ChangesSink - Calling in '%s' with %d", get_class($b), $time_each));
|
||||
|
||||
// 2 seconds hardcoded timeout!!!
|
||||
$notifications_backend = $this->backends[$i]->ChangesSink(2);
|
||||
//preppend backend delimiter
|
||||
for ($c = 0; $c < count($notifications_backend); $c++) {
|
||||
$notifications_backend[$c] = $i . $this->config['delimiter'] . $notifications_backend[$c];
|
||||
}
|
||||
$notifications = array_merge($notifications, $notifications_backend);
|
||||
$notifications_backend = $this->backends[$i]->ChangesSink($time_each);
|
||||
//preppend backend delimiter
|
||||
for ($c = 0; $c < count($notifications_backend); $c++) {
|
||||
$notifications_backend[$c] = $i . $this->config['delimiter'] . $notifications_backend[$c];
|
||||
}
|
||||
$notifications = array_merge($notifications, $notifications_backend);
|
||||
}
|
||||
} while($stopat > time() && empty($notifications));
|
||||
}
|
||||
}
|
||||
|
||||
return $notifications;
|
||||
|
@ -688,4 +704,3 @@ class BackendCombined extends Backend implements ISearchProvider {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
?>
|
|
@ -109,7 +109,8 @@ class BackendCombinedConfig {
|
|||
),
|
||||
//creating a new folder in the root folder should create a folder in one backend
|
||||
'rootcreatefolderbackend' => 'i',
|
||||
//enable to use username mapping for the different backends
|
||||
'usemapping' => false,
|
||||
);
|
||||
}
|
||||
}
|
||||
?>
|
|
@ -47,8 +47,14 @@
|
|||
*/
|
||||
|
||||
class ExportChangesCombined implements IExportChanges {
|
||||
/**
|
||||
* @var BackendCombined
|
||||
*/
|
||||
private $backend;
|
||||
private $syncstates;
|
||||
/**
|
||||
* @var IExportChanges[]
|
||||
*/
|
||||
private $exporters;
|
||||
private $importer;
|
||||
private $importwraps;
|
||||
|
@ -181,4 +187,3 @@ class ExportChangesCombined implements IExportChanges {
|
|||
ZLog::Write(LOGLEVEL_DEBUG, "ExportChangesCombined->InitializeExporter(...) success");
|
||||
}
|
||||
}
|
||||
?>
|
|
@ -131,23 +131,6 @@ class ImportChangesCombined implements IImportChanges {
|
|||
return $this->icc->ImportMessageReadFlag($id, $flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Imports a change in 'star' flag
|
||||
* This can never conflict
|
||||
*
|
||||
* @param string $id
|
||||
* @param int $flags
|
||||
*
|
||||
* @access public
|
||||
* @return boolean
|
||||
*/
|
||||
public function ImportMessageStarFlag($id, $flags) {
|
||||
if (!$this->icc) {
|
||||
ZLog::Write(LOGLEVEL_ERROR, "ImportChangesCombined->ImportMessageReadFlag() icc not configured");
|
||||
return false;
|
||||
}
|
||||
return $this->icc->ImportMessageStarFlag($id, $flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Imports a move of a message. This occurs when a user moves an item to another folder
|
||||
|
@ -168,7 +151,15 @@ class ImportChangesCombined implements IImportChanges {
|
|||
ZLog::Write(LOGLEVEL_WARN, "ImportChangesCombined->ImportMessageMove() cannot move message between two backends");
|
||||
return false;
|
||||
}
|
||||
return $this->icc->ImportMessageMove($id, $this->backend->GetBackendFolder($newfolder));
|
||||
$res = $this->icc->ImportMessageMove($id, $this->backend->GetBackendFolder($newfolder));
|
||||
|
||||
if ($res) {
|
||||
//TODO: we should add newid to new folder, instead of a full folder resync
|
||||
ZLog::Write(LOGLEVEL_DEBUG, sprintf("ImportChangesCombined->ImportMessageMove(): Force resync of dest folder (%s)", $newfolder));
|
||||
ZPushAdmin::ResyncFolder(Request::GetAuthUser(), Request::GetDeviceID(), $newfolder);
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
|
||||
|
@ -187,7 +178,7 @@ class ImportChangesCombined implements IImportChanges {
|
|||
public function ImportFolderChange($folder) {
|
||||
$id = $folder->serverid;
|
||||
$parent = $folder->parentid;
|
||||
ZLog::Write(LOGLEVEL_DEBUG, "ImportChangesCombined->ImportFolderChange() ".print_r($folder, 1));
|
||||
ZLog::Write(LOGLEVEL_DEBUG, sprintf("ImportChangesCombined->ImportFolderChange() id: '%s', parent: '%s'", $id, $parent));
|
||||
if($parent == '0') {
|
||||
if($id) {
|
||||
$backendid = $this->backend->GetBackendId($id);
|
||||
|
@ -367,5 +358,3 @@ class ImportHierarchyChangesCombinedWrap {
|
|||
return $this->ihc->ImportFolderDeletion($this->backendid.$this->backend->config['delimiter'].$id);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
4
sources/backend/imap/THANKS
Normal file
4
sources/backend/imap/THANKS
Normal file
|
@ -0,0 +1,4 @@
|
|||
*Drenalina SRL (www.drenalina.com)* sponsored the development of the following features in the BackendIMAP, any existing bug it's my fault not theirs ;-)
|
||||
Thank you very much for helping to improve it!!
|
||||
|
||||
- Meeting invitations and attendees
|
|
@ -54,6 +54,84 @@ define('IMAP_PORT', 143);
|
|||
// best cross-platform compatibility (see http://php.net/imap_open for options)
|
||||
define('IMAP_OPTIONS', '/notls/norsh');
|
||||
|
||||
|
||||
// Mark messages as read when moving to Trash.
|
||||
// BE AWARE that you will lose the unread flag, but some mail clients do this so the Trash folder doesn't get boldened
|
||||
define('IMAP_AUTOSEEN_ON_DELETE', false);
|
||||
|
||||
|
||||
// IMPORTANT: BASIC IMAP FOLDERS [ask your mail admin]
|
||||
// We can have diferent cases (case insensitive):
|
||||
// 1.
|
||||
// inbox
|
||||
// sent
|
||||
// drafts
|
||||
// trash
|
||||
// 2.
|
||||
// inbox
|
||||
// common.sent
|
||||
// common.drafts
|
||||
// common.trash
|
||||
// 3.
|
||||
// common.inbox
|
||||
// common.sent
|
||||
// common.drafts
|
||||
// common.trash
|
||||
// 4.
|
||||
// common
|
||||
// common.sent
|
||||
// common.drafts
|
||||
// common.trash
|
||||
//
|
||||
// gmail is a special case, where the default folders are under the [gmail] prefix and the folders defined by the user are under INBOX.
|
||||
// This configuration seems to work:
|
||||
// define('IMAP_FOLDER_PREFIX', '');
|
||||
// define('IMAP_FOLDER_INBOX', 'INBOX');
|
||||
// define('IMAP_FOLDER_SENT', '[Gmail]/Sent');
|
||||
// define('IMAP_FOLDER_DRAFTS', '[Gmail]/Drafts');
|
||||
// define('IMAP_FOLDER_TRASH', '[Gmail]/Trash');
|
||||
// define('IMAP_FOLDER_SPAM', '[Gmail]/Spam');
|
||||
// define('IMAP_FOLDER_ARCHIVE', '[Gmail]/All Mail');
|
||||
|
||||
// Since I know you won't configure this, I will raise an error unless you do.
|
||||
// When configured set this to true to remove the error
|
||||
define('IMAP_FOLDER_CONFIGURED', false);
|
||||
|
||||
// Folder prefix is the common part in your names (3, 4)
|
||||
define('IMAP_FOLDER_PREFIX', '');
|
||||
|
||||
// Inbox will have the preffix preppend (3 & 4 to true)
|
||||
define('IMAP_FOLDER_PREFIX_IN_INBOX', false);
|
||||
|
||||
// Inbox folder name (case doesn't matter) - (empty in 4)
|
||||
define('IMAP_FOLDER_INBOX', 'INBOX');
|
||||
|
||||
// Sent folder name (case doesn't matter)
|
||||
define('IMAP_FOLDER_SENT', 'SENT');
|
||||
|
||||
// Draft folder name (case doesn't matter)
|
||||
define('IMAP_FOLDER_DRAFT', 'DRAFTS');
|
||||
|
||||
// Trash folder name (case doesn't matter)
|
||||
define('IMAP_FOLDER_TRASH', 'TRASH');
|
||||
|
||||
// Spam folder name (case doesn't matter). Only showed as special by iOS devices
|
||||
define('IMAP_FOLDER_SPAM', 'SPAM');
|
||||
|
||||
// Archive folder name (case doesn't matter). Only showed as special by iOS devices
|
||||
define('IMAP_FOLDER_ARCHIVE', 'ARCHIVE');
|
||||
|
||||
|
||||
|
||||
// forward messages inline (default true - inlined)
|
||||
define('IMAP_INLINE_FORWARD', true);
|
||||
|
||||
// list of folders we want to exclude from sync. Names, or part of it, separated by |
|
||||
// example: dovecot.sieve|archive|spam
|
||||
define('IMAP_EXCLUDED_FOLDERS', '');
|
||||
|
||||
|
||||
|
||||
// overwrite the "from" header with some value
|
||||
// options:
|
||||
// '' - do nothing, use the From header
|
||||
|
@ -99,29 +177,6 @@ define('IMAP_FROM_LDAP_FROM', '#givenname #sn <#mail>');
|
|||
define('IMAP_FROM_LDAP_FULLNAME', '#givenname #sn');
|
||||
|
||||
|
||||
// Root folder or prefix in your IMAP server (without the separator). For example, with courier it will be INBOX, and your folder will be INBOX.Sent
|
||||
// You can use the real case
|
||||
define('IMAP_FOLDER_ROOT', 'INBOX');
|
||||
|
||||
// copy outgoing mail to this folder. If not set z-push will try the default folders
|
||||
// You can use the real case and the full path (INBOX.Sent)
|
||||
define('IMAP_FOLDER_SENT', '');
|
||||
|
||||
// Draft folder
|
||||
// You can use the real case and the full path (INBOX.Draft)
|
||||
define('IMAP_FOLDER_DRAFT', '');
|
||||
|
||||
// Trash folder
|
||||
// You can use the real case and the full path (INBOX.Trash)
|
||||
define('IMAP_FOLDER_TRASH', '');
|
||||
|
||||
// forward messages inline (default true - inlined)
|
||||
define('IMAP_INLINE_FORWARD', true);
|
||||
|
||||
// list of folders we want to exclude from sync. Names, or part of it, separated by |
|
||||
// example: dovecot.sieve|archive|spam
|
||||
define('IMAP_EXCLUDED_FOLDERS', '');
|
||||
|
||||
|
||||
// Method used for sending mail
|
||||
// mail => mail() php function
|
||||
|
@ -136,25 +191,37 @@ $imap_smtp_params = array();
|
|||
// sendmail
|
||||
//$imap_smtp_params = array('sendmail_path' => '/usr/bin/sendmail', 'sendmail_args' => '-i');
|
||||
// smtp
|
||||
// "host" - The server to connect. Default is localhost.
|
||||
// "port" - The port to connect. Default is 25.
|
||||
// "auth" - Whether or not to use SMTP authentication. Default is FALSE.
|
||||
// "username" - The username to use for SMTP authentication. "imap_username" for using the same username as the imap server
|
||||
// "password" - The password to use for SMTP authentication. "imap_password" for using the same password as the imap server
|
||||
// "localhost" - The value to give when sending EHLO or HELO. Default is localhost
|
||||
// "timeout" - The SMTP connection timeout. Default is NULL (no timeout).
|
||||
// "verp" - Whether to use VERP or not. Default is FALSE.
|
||||
// "debug" - Whether to enable SMTP debug mode or not. Default is FALSE.
|
||||
// "persist" - Indicates whether or not the SMTP connection should persist over multiple calls to the send() method.
|
||||
// "pipelining" - Indicates whether or not the SMTP commands pipelining should be used.
|
||||
// "host" - The server to connect. Default is localhost.
|
||||
// "port" - The port to connect. Default is 25.
|
||||
// "auth" - Whether or not to use SMTP authentication. Default is FALSE.
|
||||
// "username" - The username to use for SMTP authentication. "imap_username" for using the same username as the imap server
|
||||
// "password" - The password to use for SMTP authentication. "imap_password" for using the same password as the imap server
|
||||
// "localhost" - The value to give when sending EHLO or HELO. Default is localhost
|
||||
// "timeout" - The SMTP connection timeout. Default is NULL (no timeout).
|
||||
// "verp" - Whether to use VERP or not. Default is FALSE.
|
||||
// "debug" - Whether to enable SMTP debug mode or not. Default is FALSE.
|
||||
// "persist" - Indicates whether or not the SMTP connection should persist over multiple calls to the send() method.
|
||||
// "pipelining" - Indicates whether or not the SMTP commands pipelining should be used.
|
||||
// "verify_peer" - Require verification of SSL certificate used. Default is TRUE.
|
||||
// "verify_peer_name" - Require verification of peer name. Default is TRUE.
|
||||
// "allow_self_signed" - Allow self-signed certificates. Requires verify_peer. Default is FALSE.
|
||||
//$imap_smtp_params = array('host' => 'localhost', 'port' => 25, 'auth' => false);
|
||||
// If you want to use SSL with port 25 or port 465 you must preppend "ssl://" before the hostname or IP of your SMTP server
|
||||
// IMPORTANT: To use SSL you must use PHP 5.1 or later, install openssl libs and use ssl:// within the host variable
|
||||
// IMPORTANT: To use SSL with PHP 5.6 you should set verify_peer, verify_peer_name and allow_self_signed
|
||||
//$imap_smtp_params = array('host' => 'ssl://localhost', 'port' => 465, 'auth' => true, 'username' => 'imap_username', 'password' => 'imap_password');
|
||||
|
||||
|
||||
|
||||
// If you are using IMAP_SMTP_METHOD = mail or sendmail and your sent messages are not correctly displayed you can change this to "\n".
|
||||
// BUT, it doesn't comply with RFC 2822 and will break if using smtp method
|
||||
define('MAIL_MIMEPART_CRLF', "\r\n");
|
||||
|
||||
?>
|
||||
|
||||
// A file containing file mime types->extension mappings.
|
||||
// SELINUX users: make sure the file has a security context accesible by your apache/php-fpm process
|
||||
define('SYSTEM_MIME_TYPES_MAPPING', '/etc/mime.types');
|
||||
|
||||
|
||||
// Use BackendCalDAV for Meetings. You cannot hope to get that functionality working without a caldav backend.
|
||||
define('IMAP_MEETING_USE_CALDAV', false);
|
File diff suppressed because it is too large
Load diff
344
sources/backend/imap/mime_calendar.php
Normal file
344
sources/backend/imap/mime_calendar.php
Normal file
|
@ -0,0 +1,344 @@
|
|||
<?php
|
||||
|
||||
function create_calendar_dav($data) {
|
||||
ZLog::Write(LOGLEVEL_DEBUG, "BackendIMAP->create_calendar_dav(): Creating calendar event");
|
||||
|
||||
if (defined('IMAP_MEETING_USE_CALDAV') && IMAP_MEETING_USE_CALDAV) {
|
||||
$caldav = new BackendCalDAV();
|
||||
if ($caldav->Logon(Request::GetAuthUser(), Request::GetAuthDomain(), Request::GetAuthPassword())) {
|
||||
$etag = $caldav->CreateUpdateCalendar($data);
|
||||
ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendIMAP->create_calendar_dav(): Calendar created with etag '%s' and data <%s>", $etag, $data));
|
||||
$caldav->Logoff();
|
||||
}
|
||||
else {
|
||||
ZLog::Write(LOGLEVEL_ERROR, "BackendIMAP->create_calendar_dav(): Error connecting with BackendCalDAV");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function delete_calendar_dav($uid) {
|
||||
ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendIMAP->delete_calendar_dav('%s'): Deleting calendar event", $uid));
|
||||
|
||||
if ($uid === false) {
|
||||
ZLog::Write(LOGLEVEL_WARN, "BackendIMAP->delete_calendar_dav(): UID not found; report the full calendar object to developers");
|
||||
}
|
||||
else {
|
||||
if (defined('IMAP_MEETING_USE_CALDAV') && IMAP_MEETING_USE_CALDAV) {
|
||||
$caldav = new BackendCalDAV();
|
||||
if ($caldav->Logon(Request::GetAuthUser(), Request::GetAuthDomain(), Request::GetAuthPassword())) {
|
||||
$events = $caldav->FindCalendar($uid);
|
||||
if (count($events) == 1) {
|
||||
$href = $events[0]["href"];
|
||||
ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendIMAP->delete_calendar_dav(): found event with href '%s', deleting", $href));
|
||||
// Delete event
|
||||
$res = $caldav->DeleteCalendar($href);
|
||||
if ($res) {
|
||||
ZLog::Write(LOGLEVEL_DEBUG, "BackendIMAP->delete_calendar_dav(): event deleted");
|
||||
}
|
||||
else {
|
||||
ZLog::Write(LOGLEVEL_ERROR, "BackendIMAP->delete_calendar_dav(): error removing event, we will end with zombie events");
|
||||
}
|
||||
$caldav->Logoff();
|
||||
}
|
||||
else {
|
||||
ZLog::Write(LOGLEVEL_ERROR, "BackendIMAP->delete_calendar_dav(): event not found, we will end with zombie events");
|
||||
}
|
||||
}
|
||||
else {
|
||||
ZLog::Write(LOGLEVEL_ERROR, "BackendIMAP->delete_calendar_dav(): Error connecting with BackendCalDAV");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function update_calendar_attendee($uid, $mailto, $status) {
|
||||
ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendIMAP->update_calendar_attendee('%s', '%s', '%s'): Updating calendar event attendee", $uid, $mailto, $status));
|
||||
$updated = false;
|
||||
|
||||
if ($uid === false) {
|
||||
ZLog::Write(LOGLEVEL_WARN, "BackendIMAP->update_calendar_attendee(): UID not found; report the full calendar object to developers");
|
||||
}
|
||||
else {
|
||||
if (defined('IMAP_MEETING_USE_CALDAV') && IMAP_MEETING_USE_CALDAV) {
|
||||
$caldav = new BackendCalDAV();
|
||||
if ($caldav->Logon(Request::GetAuthUser(), Request::GetAuthDomain(), Request::GetAuthPassword())) {
|
||||
$events = $caldav->FindCalendar($uid);
|
||||
if (count($events) == 1) {
|
||||
$href = $events[0]["href"];
|
||||
$etag = $events[0]["etag"];
|
||||
ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendIMAP->update_calendar_attendee(): found event with href '%s' etag '%s'; updating", $href, $etag));
|
||||
|
||||
// Get Attendee status
|
||||
$old_status = "";
|
||||
|
||||
if (strcasecmp($old_status, $status) != 0) {
|
||||
ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendIMAP->update_calendar_attendee(): Before <%s>", $events[0]["data"]));
|
||||
$ical = new iCalComponent();
|
||||
$ical->ParseFrom($events[0]["data"]);
|
||||
$ical->SetCPParameterValue("VEVENT", "ATTENDEE", "PARTSTAT", strtoupper($status), $mailto);
|
||||
ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendIMAP->update_calendar_attendee(): After <%s>", $ical->Render()));
|
||||
$etag = $caldav->CreateUpdateCalendar($ical->Render(), $href, $etag);
|
||||
ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendIMAP->update_calendar_attendee(): Calendar updated with etag '%s'", $etag));
|
||||
// Update new status
|
||||
$updated = true;
|
||||
}
|
||||
|
||||
$caldav->Logoff();
|
||||
}
|
||||
else {
|
||||
ZLog::Write(LOGLEVEL_ERROR, "BackendIMAP->update_calendar_attendee(): event not found or duplicated event");
|
||||
}
|
||||
}
|
||||
else {
|
||||
ZLog::Write(LOGLEVEL_ERROR, "BackendIMAP->update_calendar_attendee(): Error connecting with BackendCalDAV");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $updated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect if one message has one VCALENDAR part
|
||||
*
|
||||
* @param Mail_mimeDecode $message
|
||||
* @return boolean
|
||||
* @access private
|
||||
*/
|
||||
function has_calendar_object($message) {
|
||||
if (is_calendar($message)) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
if(isset($message->parts)) {
|
||||
for ($i = 0; $i < count($message->parts); $i++) {
|
||||
if (is_calendar($message->parts[$i])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Detect if the message-part is VCALENDAR
|
||||
* Content-Type: text/calendar;
|
||||
*
|
||||
* @param Mail_mimeDecode $message
|
||||
* @return boolean
|
||||
* @access private
|
||||
*/
|
||||
function is_calendar($message) {
|
||||
return isset($message->ctype_primary) && isset($message->ctype_secondary) && $message->ctype_primary == "text" && $message->ctype_secondary == "calendar";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Converts a text/calendar part into SyncMeetingRequest
|
||||
* This is called on received messages, it's not called for events generated from the mobile
|
||||
*
|
||||
* @access private
|
||||
* @param $part MIME part
|
||||
* @param $output SyncMail object
|
||||
* @param $is_sent_folder boolean
|
||||
*/
|
||||
function parse_meeting_calendar($part, &$output, $is_sent_folder) {
|
||||
$ical = new iCalComponent();
|
||||
$ical->ParseFrom($part->body);
|
||||
ZLog::Write(LOGLEVEL_WBXML, sprintf("BackendIMAP->parse_meeting_calendar(): %s", $part->body));
|
||||
|
||||
// Get UID
|
||||
$uid = false;
|
||||
$props = $ical->GetPropertiesByPath("VEVENT/UID");
|
||||
if (count($props) > 0) {
|
||||
$uid = $props[0]->Value();
|
||||
}
|
||||
|
||||
if (isset($part->ctype_parameters["method"])) {
|
||||
switch (strtolower($part->ctype_parameters["method"])) {
|
||||
case "cancel":
|
||||
$output->messageclass = "IPM.Schedule.Meeting.Canceled";
|
||||
$output->meetingrequest->disallownewtimeproposal = 1;
|
||||
ZLog::Write(LOGLEVEL_DEBUG, "BackendIMAP->parse_meeting_calendar(): Event canceled, removing calendar object");
|
||||
delete_calendar_dav($uid);
|
||||
break;
|
||||
case "counter":
|
||||
ZLog::Write(LOGLEVEL_DEBUG, "BackendIMAP->parse_meeting_calendar(): Counter received");
|
||||
$output->messageclass = "IPM.Schedule.Meeting.Resp.Tent";
|
||||
$output->meetingrequest->disallownewtimeproposal = 0;
|
||||
break;
|
||||
case "reply":
|
||||
ZLog::Write(LOGLEVEL_DEBUG, "BackendIMAP->parse_meeting_calendar(): Reply received");
|
||||
$props = $ical->GetPropertiesByPath('VEVENT/ATTENDEE');
|
||||
|
||||
for ($i = 0; $i < count($props); $i++) {
|
||||
$mailto = $props[$i]->Value();
|
||||
$props_params = $props[$i]->Parameters();
|
||||
$status = strtolower($props_params["PARTSTAT"]);
|
||||
if (!$is_sent_folder) {
|
||||
// Only evaluate received replies, not sent
|
||||
$res = update_calendar_attendee($uid, $mailto, $status);
|
||||
}
|
||||
else {
|
||||
$res = true;
|
||||
}
|
||||
if ($res) {
|
||||
// Only set messageclass for replies changing my calendar object
|
||||
switch ($status) {
|
||||
case "accepted":
|
||||
$output->messageclass = "IPM.Schedule.Meeting.Resp.Pos";
|
||||
ZLog::Write(LOGLEVEL_DEBUG, "BackendIMAP->parse_meeting_calendar(): Update attendee -> accepted");
|
||||
break;
|
||||
case "needs-action":
|
||||
$output->messageclass = "IPM.Schedule.Meeting.Resp.Tent";
|
||||
ZLog::Write(LOGLEVEL_DEBUG, "BackendIMAP->parse_meeting_calendar(): Update attendee -> needs-action");
|
||||
break;
|
||||
case "tentative":
|
||||
$output->messageclass = "IPM.Schedule.Meeting.Resp.Tent";
|
||||
ZLog::Write(LOGLEVEL_DEBUG, "BackendIMAP->parse_meeting_calendar(): Update attendee -> tentative");
|
||||
break;
|
||||
case "declined":
|
||||
$output->messageclass = "IPM.Schedule.Meeting.Resp.Neg";
|
||||
ZLog::Write(LOGLEVEL_DEBUG, "BackendIMAP->parse_meeting_calendar(): Update attendee -> declined");
|
||||
break;
|
||||
default:
|
||||
ZLog::Write(LOGLEVEL_WARN, sprintf("BackendIMAP->parse_meeting_calendar() - Unknown reply status <%s>, please report it to the developers", $status));
|
||||
$output->messageclass = "IPM.Appointment";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
$output->meetingrequest->disallownewtimeproposal = 1;
|
||||
break;
|
||||
case "request":
|
||||
$output->messageclass = "IPM.Schedule.Meeting.Request";
|
||||
$output->meetingrequest->disallownewtimeproposal = 0;
|
||||
ZLog::Write(LOGLEVEL_DEBUG, "BackendIMAP->parse_meeting_calendar(): New request");
|
||||
// New meeting, we don't create it now, because we need to confirm it first, but if we don't create it we won't see it in the calendar
|
||||
break;
|
||||
default:
|
||||
ZLog::Write(LOGLEVEL_WARN, sprintf("BackendIMAP->parse_meeting_calendar() - Unknown method <%s>, please report it to the developers", strtolower($part->headers["method"])));
|
||||
$output->messageclass = "IPM.Appointment";
|
||||
$output->meetingrequest->disallownewtimeproposal = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
ZLog::Write(LOGLEVEL_WARN, sprintf("BackendIMAP->parse_meeting_calendar() - No method header, please report it to the developers"));
|
||||
$output->messageclass = "IPM.Appointment";
|
||||
}
|
||||
|
||||
$props = $ical->GetPropertiesByPath('VEVENT/DTSTAMP');
|
||||
if (count($props) == 1) {
|
||||
$output->meetingrequest->dtstamp = Utils::MakeUTCDate($props[0]->Value());
|
||||
}
|
||||
$props = $ical->GetPropertiesByPath('VEVENT/UID');
|
||||
if (count($props) == 1) {
|
||||
$output->meetingrequest->globalobjid = $props[0]->Value();
|
||||
}
|
||||
$props = $ical->GetPropertiesByPath('VEVENT/DTSTART');
|
||||
if (count($props) == 1) {
|
||||
$output->meetingrequest->starttime = Utils::MakeUTCDate($props[0]->Value());
|
||||
if (strlen($props[0]->Value()) == 8) {
|
||||
$output->meetingrequest->alldayevent = 1;
|
||||
}
|
||||
}
|
||||
$props = $ical->GetPropertiesByPath('VEVENT/DTEND');
|
||||
if (count($props) == 1) {
|
||||
$output->meetingrequest->endtime = Utils::MakeUTCDate($props[0]->Value());
|
||||
if (strlen($props[0]->Value()) == 8) {
|
||||
$output->meetingrequest->alldayevent = 1;
|
||||
}
|
||||
}
|
||||
$props = $ical->GetPropertiesByPath('VEVENT/ORGANIZER');
|
||||
if (count($props) == 1) {
|
||||
$output->meetingrequest->organizer = str_ireplace("MAILTO:", "", $props[0]->Value());
|
||||
}
|
||||
$props = $ical->GetPropertiesByPath('VEVENT/LOCATION');
|
||||
if (count($props) == 1) {
|
||||
$output->meetingrequest->location = $props[0]->Value();
|
||||
}
|
||||
$props = $ical->GetPropertiesByPath('VEVENT/CLASS');
|
||||
if (count($props) == 1) {
|
||||
switch ($props[0]->Value()) {
|
||||
case "PUBLIC":
|
||||
$output->meetingrequest->sensitivity = "0";
|
||||
break;
|
||||
case "PRIVATE":
|
||||
$output->meetingrequest->sensitivity = "2";
|
||||
break;
|
||||
case "CONFIDENTIAL":
|
||||
$output->meetingrequest->sensitivity = "3";
|
||||
break;
|
||||
default:
|
||||
ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendIMAP->parse_meeting_calendar() - No sensitivity class. Using 2"));
|
||||
$output->meetingrequest->sensitivity = "2";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Get $tz from first timezone
|
||||
$props = $ical->GetPropertiesByPath("VTIMEZONE/TZID");
|
||||
if (count($props) > 0) {
|
||||
// TimeZones shouldn't have dots
|
||||
$tzname = str_replace(".", "", $props[0]->Value());
|
||||
$tz = TimezoneUtil::GetFullTZFromTZName($tzname);
|
||||
}
|
||||
else {
|
||||
$tz = TimezoneUtil::GetFullTZ();
|
||||
}
|
||||
$output->meetingrequest->timezone = base64_encode(TimezoneUtil::getSyncBlobFromTZ($tz));
|
||||
|
||||
// Fixed values
|
||||
$output->meetingrequest->instancetype = 0;
|
||||
$output->meetingrequest->responserequested = 1;
|
||||
$output->meetingrequest->busystatus = 2;
|
||||
|
||||
// TODO: reminder
|
||||
$output->meetingrequest->reminder = "";
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Modify a text/calendar part to transform it in a reply
|
||||
*
|
||||
* @access private
|
||||
* @param $part MIME part
|
||||
* @param $response Response numeric value
|
||||
* @param $condition_value string
|
||||
* @return string MIME text/calendar
|
||||
*/
|
||||
function reply_meeting_calendar($part, $response, $username) {
|
||||
$status_attendee = "ACCEPTED"; // 1 or default is ACCEPTED
|
||||
$status_event = "CONFIRMED";
|
||||
switch ($response) {
|
||||
case 1:
|
||||
$status_attendee = "ACCEPTED";
|
||||
$status_event = "CONFIRMED";
|
||||
break;
|
||||
case 2:
|
||||
$status_attendee = $status_event = "TENTATIVE";
|
||||
break;
|
||||
case 3:
|
||||
// We won't hit this case ever, because we won't create an event if we are rejecting it
|
||||
$status_attendee = "DECLINED";
|
||||
$status_event = "CANCELLED";
|
||||
break;
|
||||
}
|
||||
|
||||
$ical = new iCalComponent();
|
||||
$ical->ParseFrom($part->body);
|
||||
|
||||
$ical->SetPValue("METHOD", "REPLY");
|
||||
$ical->SetCPParameterValue("VEVENT", "STATUS", $status_event, null);
|
||||
// Update my information as attendee, but only mine
|
||||
$ical->SetCPParameterValue("VEVENT", "ATTENDEE", "PARTSTAT", $status_attendee, sprintf("MAILTO:%s", $username));
|
||||
$ical->SetCPParameterValue("VEVENT", "ATTENDEE", "RSVP", null, sprintf("MAILTO:%s", $username));
|
||||
|
||||
return $ical->Render();
|
||||
}
|
|
@ -70,6 +70,7 @@ function add_sub_part(&$email, $part) {
|
|||
}
|
||||
//FIXME: dfilename => filename
|
||||
if (isset($part->d_parameters)) {
|
||||
$params['headers_charset'] = 'utf-8';
|
||||
foreach ($part->d_parameters as $k => $v) {
|
||||
$params[$k] = $v;
|
||||
}
|
||||
|
@ -252,31 +253,9 @@ function build_mime_message($message) {
|
|||
return $built_message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect if the message-part is VCALENDAR
|
||||
* Content-Type: text/calendar;
|
||||
*
|
||||
* @param Mail_mimeDecode $message
|
||||
* @return boolean
|
||||
* @access public
|
||||
*/
|
||||
function is_calendar($message) {
|
||||
$res = false;
|
||||
|
||||
if (isset($message->ctype_primary) && isset($message->ctype_secondary)) {
|
||||
if ($message->ctype_primary == "text" && $message->ctype_secondary == "calendar") {
|
||||
$res = true;
|
||||
}
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Detect if the message-part is SMIME
|
||||
* Content-Type: multipart/signed;
|
||||
* Content-Type: application/pkcs7-mime;
|
||||
*
|
||||
* @param Mail_mimeDecode $message
|
||||
* @return boolean
|
||||
|
@ -286,10 +265,43 @@ function is_smime($message) {
|
|||
$res = false;
|
||||
|
||||
if (isset($message->ctype_primary) && isset($message->ctype_secondary)) {
|
||||
if (($message->ctype_primary == "multipart" && $message->ctype_secondary == "signed") || ($message->ctype_primary == "application" && $message->ctype_secondary == "pkcs7-mime")) {
|
||||
$res = true;
|
||||
$smime_types = array(array("multipart", "signed"), array("application", "pkcs7-mime"), array("application", "x-pkcs7-mime"), array("multipart", "encrypted"));
|
||||
for ($i = 0; $i < count($smime_types) && !$res; $i++) {
|
||||
$res = ($message->ctype_primary == $smime_types[$i][0] && $message->ctype_secondary == $smime_types[$i][1]);
|
||||
}
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Detect if the message-part is SMIME, encrypted but not signed
|
||||
* #190, KD 2015-06-04
|
||||
*
|
||||
* @param Mail_mimeDecode $message
|
||||
* @return boolean
|
||||
* @access public
|
||||
*/
|
||||
function is_encrypted($message) {
|
||||
$res = false;
|
||||
|
||||
if (is_smime($message) && !($message->ctype_primary == "multipart" && $message->ctype_secondary == "signed")) {
|
||||
$res = true;
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Detect if the message is multipart.
|
||||
* #198, KD 2015-06-15
|
||||
*
|
||||
* @param Mail_mimeDecode $message
|
||||
* @return boolean
|
||||
* @access public
|
||||
*/
|
||||
function is_multipart($message) {
|
||||
return isset($message->ctype_primary) && $message->ctype_primary == "multipart";
|
||||
}
|
232
sources/backend/imap/user_identity.php
Normal file
232
sources/backend/imap/user_identity.php
Normal file
|
@ -0,0 +1,232 @@
|
|||
<?php
|
||||
|
||||
|
||||
/**
|
||||
* Returns the default value for "From"
|
||||
*
|
||||
* @access private
|
||||
* @return string
|
||||
*/
|
||||
function getDefaultFromValue($username, $domain) {
|
||||
$v = "";
|
||||
|
||||
if (defined('IMAP_DEFAULTFROM')) {
|
||||
switch (IMAP_DEFAULTFROM) {
|
||||
case 'username':
|
||||
$v = $username;
|
||||
break;
|
||||
case 'domain':
|
||||
$v = $domain;
|
||||
break;
|
||||
case 'ldap':
|
||||
$v = getIdentityFromLdap($username, $domain, IMAP_FROM_LDAP_FROM, true);
|
||||
break;
|
||||
case 'sql':
|
||||
$v = getIdentityFromSql($username, $domain, IMAP_FROM_SQL_FROM, true);
|
||||
break;
|
||||
case 'passwd':
|
||||
$v = getIdentityFromPasswd($username, $domain, 'FROM', true);
|
||||
break;
|
||||
default:
|
||||
$v = $username . IMAP_DEFAULTFROM;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $v;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default value for "FullName"
|
||||
*
|
||||
* @access private
|
||||
* @param string $username Username
|
||||
* @return string
|
||||
*/
|
||||
function getDefaultFullNameValue($username, $domain) {
|
||||
$v = $username;
|
||||
|
||||
if (defined('IMAP_DEFAULTFROM')) {
|
||||
switch (IMAP_DEFAULTFROM) {
|
||||
case 'ldap':
|
||||
$v = getIdentityFromSql($username, $domain, IMAP_FROM_LDAP_FULLNAME, false);
|
||||
break;
|
||||
case 'sql':
|
||||
$v = getIdentityFromSql($username, $domain, IMAP_FROM_SQL_FULLNAME, false);
|
||||
break;
|
||||
case 'passwd':
|
||||
$v = getIdentityFromPasswd($username, $domain, 'FULLNAME', false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $v;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the "From"/"FullName" value stored in a LDAP server
|
||||
*
|
||||
* @access private
|
||||
* @params string $username username value
|
||||
* @params string $domain domain value
|
||||
* @params string $identity pattern to fill with ldap values
|
||||
* @params boolean $encode if the result should be encoded as a header
|
||||
* @return string
|
||||
*/
|
||||
function getIdentityFromLdap($username, $domain, $identity, $encode = true) {
|
||||
$ret_value = $username;
|
||||
|
||||
$ldap_conn = null;
|
||||
try {
|
||||
$ldap_conn = ldap_connect(IMAP_FROM_LDAP_SERVER, IMAP_FROM_LDAP_SERVER_PORT);
|
||||
if ($ldap_conn) {
|
||||
ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendIMAP->getIdentityFromLdap() - Connected to LDAP"));
|
||||
ldap_set_option($ldap_conn, LDAP_OPT_PROTOCOL_VERSION, 3);
|
||||
ldap_set_option($ldap_conn, LDAP_OPT_REFERRALS, 0);
|
||||
$ldap_bind = ldap_bind($ldap_conn, IMAP_FROM_LDAP_USER, IMAP_FROM_LDAP_PASSWORD);
|
||||
|
||||
if ($ldap_bind) {
|
||||
ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendIMAP->getIdentityFromLdap() - Authenticated in LDAP"));
|
||||
$filter = str_replace('#username', $username, str_replace('#domain', $domain, IMAP_FROM_LDAP_QUERY));
|
||||
ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendIMAP->getIdentityFromLdap() - Searching From with filter: %s", $filter));
|
||||
$search = ldap_search($ldap_conn, IMAP_FROM_LDAP_BASE, $filter, unserialize(IMAP_FROM_LDAP_FIELDS));
|
||||
$items = ldap_get_entries($ldap_conn, $search);
|
||||
if ($items['count'] > 0) {
|
||||
$ret_value = $identity;
|
||||
ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendIMAP->getIdentityFromLdap() - Found entry in LDAP. Generating From"));
|
||||
// We get the first object. It's your responsability to make the query unique
|
||||
foreach (unserialize(IMAP_FROM_LDAP_FIELDS) as $field) {
|
||||
$ret_value = str_replace('#'.$field, $items[0][$field][0], $ret_value);
|
||||
}
|
||||
if ($encode) {
|
||||
$ret_value = encodeFrom($ret_value);
|
||||
}
|
||||
}
|
||||
else {
|
||||
ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendIMAP->getIdentityFromLdap() - No entry found in LDAP"));
|
||||
}
|
||||
}
|
||||
else {
|
||||
ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendIMAP->getIdentityFromLdap() - Not authenticated in LDAP server"));
|
||||
}
|
||||
}
|
||||
else {
|
||||
ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendIMAP->getIdentityFromLdap() - Not connected to LDAP server"));
|
||||
}
|
||||
}
|
||||
catch(Exception $ex) {
|
||||
ZLog::Write(LOGLEVEL_WARN, sprintf("BackendIMAP->getIdentityFromLdap() - Error getting From value from LDAP server: %s", $ex));
|
||||
}
|
||||
|
||||
if ($ldap_conn != null) {
|
||||
ldap_close($ldap_conn);
|
||||
}
|
||||
|
||||
return $ret_value;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generate the "From" value stored in a SQL Database
|
||||
*
|
||||
* @access private
|
||||
* @params string $username username value
|
||||
* @params string $domain domain value
|
||||
* @return string
|
||||
*/
|
||||
function getIdentityFromSql($username, $domain, $identity, $encode = true) {
|
||||
$ret_value = $username;
|
||||
|
||||
$dbh = $sth = $record = null;
|
||||
try {
|
||||
$dbh = new PDO(IMAP_FROM_SQL_DSN, IMAP_FROM_SQL_USER, IMAP_FROM_SQL_PASSWORD, unserialize(IMAP_FROM_SQL_OPTIONS));
|
||||
ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendIMAP->getIdentityFromSql() - Connected to SQL Database"));
|
||||
|
||||
$sql = str_replace('#username', $username, str_replace('#domain', $domain, IMAP_FROM_SQL_QUERY));
|
||||
ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendIMAP->getIdentityFromSql() - Searching From with filter: %s", $sql));
|
||||
$sth = $dbh->prepare($sql);
|
||||
$sth->execute();
|
||||
$record = $sth->fetch(PDO::FETCH_ASSOC);
|
||||
if ($record) {
|
||||
ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendIMAP->getIdentityFromSql() - Found entry in SQL Database. Generating From"));
|
||||
$ret_value = $identity;
|
||||
foreach (unserialize(IMAP_FROM_SQL_FIELDS) as $field) {
|
||||
$ret_value = str_replace('#'.$field, $record[$field], $ret_value);
|
||||
}
|
||||
if ($encode) {
|
||||
$ret_value = encodeFrom($ret_value);
|
||||
}
|
||||
}
|
||||
else {
|
||||
ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendIMAP->getIdentityFromSql() - No entry found in SQL Database"));
|
||||
}
|
||||
}
|
||||
catch(PDOException $ex) {
|
||||
ZLog::Write(LOGLEVEL_WARN, sprintf("BackendIMAP->getIdentityFromSql() - Error getting From value from SQL Database: %s", $ex));
|
||||
}
|
||||
|
||||
$dbh = $sth = $record = null;
|
||||
|
||||
return $ret_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the "From" value from the local posix passwd database
|
||||
*
|
||||
* @access private
|
||||
* @params string $username username value
|
||||
* @params string $domain domain value
|
||||
* @return string
|
||||
*/
|
||||
function getIdentityFromPasswd($username, $domain, $identity, $encode = true) {
|
||||
$ret_value = $username;
|
||||
|
||||
try {
|
||||
ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendIMAP->getIdentityFromPasswd() - Fetching info for user %s", $username));
|
||||
|
||||
$local_user = posix_getpwnam($username);
|
||||
if ($local_user) {
|
||||
$tmp = $local_user['gecos'];
|
||||
$tmp = explode(',', $tmp);
|
||||
$name = $tmp[0];
|
||||
unset($tmp);
|
||||
|
||||
switch ($identity) {
|
||||
case 'FROM':
|
||||
if (strlen($domain) > 0) {
|
||||
$ret_value = sprintf("%s <%s@%s>", $name, $username, $domain);
|
||||
} else {
|
||||
ZLog::Write(LOGLEVEL_WARN, sprintf("BackendIMAP->getIdentityFromPasswd() - No domain passed. Cannot construct From address."));
|
||||
}
|
||||
break;
|
||||
case 'FULLNAME':
|
||||
$ret_value = sprintf("%s", $name);
|
||||
break;
|
||||
}
|
||||
if ($encode) {
|
||||
$ret_value = encodeFrom($ret_value);
|
||||
}
|
||||
} else {
|
||||
ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendIMAP->getIdentityFromPasswd() - No entry found in Password database"));
|
||||
}
|
||||
}
|
||||
catch(Exception $ex) {
|
||||
ZLog::Write(LOGLEVEL_WARN, sprintf("BackendIMAP->getIdentityFromPasswd() - Error getting From value from passwd database: %s", $ex));
|
||||
}
|
||||
|
||||
return $ret_value;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Encode the From value as Base64
|
||||
*
|
||||
* @access private
|
||||
* @param string $from From value
|
||||
* @return string
|
||||
*/
|
||||
function encodeFrom($from) {
|
||||
$items = explode("<", $from);
|
||||
$name = trim($items[0]);
|
||||
return "=?UTF-8?B?" . base64_encode($name) . "?= <" . $items[1];
|
||||
}
|
|
@ -55,6 +55,4 @@ define('LDAP_SERVER_PORT', '389');
|
|||
define('LDAP_USER_DN', 'uid=%u,ou=mailaccount,dc=phppush,dc=com');
|
||||
|
||||
// LDAP BASE DNS
|
||||
define('LDAP_BASE_DNS', 'Contacts:ou=addressbook,uid=%u,ou=mailaccount,dc=phppush,dc=com'); //Multiple values separator is |
|
||||
|
||||
?>
|
||||
define('LDAP_BASE_DNS', 'Contacts:ou=addressbook,uid=%u,ou=mailaccount,dc=phppush,dc=com'); //Multiple values separator is |
|
|
@ -48,8 +48,6 @@
|
|||
// config file
|
||||
require_once("backend/ldap/config.php");
|
||||
|
||||
include_once('lib/default/diffbackend/diffbackend.php');
|
||||
|
||||
class BackendLDAP extends BackendDiff {
|
||||
|
||||
private $ldap_link;
|
||||
|
@ -521,10 +519,6 @@ class BackendLDAP extends BackendDiff {
|
|||
return false;
|
||||
}
|
||||
|
||||
public function SetStarFlag($folderid, $id, $flags, $contentParameters) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public function DeleteMessage($folderid, $id, $contentParameters) {
|
||||
ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendLDAP->DeleteMessage('%s','%s')", $folderid, $id));
|
||||
$base_dns = explode("|", LDAP_BASE_DNS);
|
||||
|
@ -580,5 +574,4 @@ class BackendLDAP extends BackendDiff {
|
|||
public function GetSupportedASVersion() {
|
||||
return ZPush::ASV_14;
|
||||
}
|
||||
}
|
||||
?>
|
||||
}
|
|
@ -47,5 +47,3 @@
|
|||
|
||||
define('MAILDIR_BASE', '/tmp');
|
||||
define('MAILDIR_SUBDIR', 'Maildir');
|
||||
|
||||
?>
|
|
@ -56,11 +56,6 @@
|
|||
// config file
|
||||
require_once("backend/maildir/config.php");
|
||||
|
||||
include_once('lib/default/diffbackend/diffbackend.php');
|
||||
|
||||
include_once('include/mimeDecode.php');
|
||||
require_once('include/z_RFC822.php');
|
||||
|
||||
class BackendMaildir extends BackendDiff {
|
||||
/**----------------------------------------------------------------------------------------------------------
|
||||
* default backend methods
|
||||
|
@ -141,7 +136,6 @@ class BackendMaildir extends BackendDiff {
|
|||
|
||||
$message = Mail_mimeDecode::decode(array('decode_headers' => true, 'decode_bodies' => true, 'include_bodies' => true, 'input' => $rfc822, 'crlf' => "\n", 'charset' => 'utf-8'));
|
||||
|
||||
include_once('include/stringstreamwrapper.php');
|
||||
$attachment = new SyncItemOperationsAttachment();
|
||||
$attachment->data = StringStreamWrapper::Open($message->parts[$part]->body);
|
||||
if (isset($message->parts[$part]->ctype_primary) && isset($message->parts[$part]->ctype_secondary))
|
||||
|
@ -542,22 +536,6 @@ class BackendMaildir extends BackendDiff {
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the 'star' flag of a message on disk
|
||||
*
|
||||
* @param string $folderid id of the folder
|
||||
* @param string $id id of the message
|
||||
* @param int $flags star flag of the message
|
||||
* @param ContentParameters $contentParameters
|
||||
*
|
||||
* @access public
|
||||
* @return boolean status of the operation
|
||||
* @throws StatusException could throw specific SYNC_STATUS_* exceptions
|
||||
*/
|
||||
public function SetStarFlag($folderid, $id, $flags, $contentParameters) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the user has requested to delete (really delete) a message
|
||||
*
|
||||
|
@ -735,6 +713,4 @@ class BackendMaildir extends BackendDiff {
|
|||
private function getPath() {
|
||||
return MAILDIR_BASE . "/" . $this->store . "/" . MAILDIR_SUBDIR . "/cur";
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
}
|
|
@ -72,4 +72,3 @@ $ldap_field_map = array(
|
|||
SYNC_GAL_MOBILEPHONE => 'mobile',
|
||||
SYNC_GAL_EMAILADDRESS => 'mail',
|
||||
);
|
||||
?>
|
|
@ -194,5 +194,4 @@ class BackendSearchLDAP implements ISearchProvider {
|
|||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
?>
|
||||
}
|
|
@ -46,5 +46,3 @@
|
|||
// **********************
|
||||
|
||||
define('VCARDDIR_DIR', '/home/%u/.kde/share/apps/kabc/stdvcf');
|
||||
|
||||
?>
|
|
@ -44,8 +44,6 @@
|
|||
// config file
|
||||
require_once("backend/vcarddir/config.php");
|
||||
|
||||
include_once('lib/default/diffbackend/diffbackend.php');
|
||||
|
||||
class BackendVCardDir extends BackendDiff {
|
||||
/**----------------------------------------------------------------------------------------------------------
|
||||
* default backend methods
|
||||
|
@ -597,22 +595,6 @@ class BackendVCardDir extends BackendDiff {
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the 'star' flag of a message on disk
|
||||
*
|
||||
* @param string $folderid id of the folder
|
||||
* @param string $id id of the message
|
||||
* @param int $flags star flag of the message
|
||||
* @param ContentParameters $contentParameters
|
||||
*
|
||||
* @access public
|
||||
* @return boolean status of the operation
|
||||
* @throws StatusException could throw specific SYNC_STATUS_* exceptions
|
||||
*/
|
||||
public function SetStarFlag($folderid, $id, $flags, $contentParameters) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the user has requested to delete (really delete) a message
|
||||
*
|
||||
|
@ -693,5 +675,4 @@ class BackendVCardDir extends BackendDiff {
|
|||
$data = str_replace(array('\\\\', '\\;', '\\,', '\\n','\\N'),array('\\', ';', ',', "\n", "\n"),$data);
|
||||
return $data;
|
||||
}
|
||||
};
|
||||
?>
|
||||
}
|
|
@ -47,5 +47,3 @@
|
|||
|
||||
// Defines the server to which we want to connect
|
||||
define('MAPI_SERVER', 'file:///var/run/zarafa');
|
||||
|
||||
?>
|
|
@ -12,7 +12,7 @@
|
|||
*
|
||||
* Created : 14.02.2011
|
||||
*
|
||||
* Copyright 2007 - 2013 Zarafa Deutschland GmbH
|
||||
* Copyright 2007 - 2013, 2015 Zarafa Deutschland GmbH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
|
@ -210,7 +210,7 @@ class ExportChangesICS implements IExportChanges{
|
|||
throw new StatusException("ExportChangesICS->InitializeExporter(): Error, exporter or essential data not available", SYNC_FSSTATUS_CODEUNKNOWN, null, LOGLEVEL_ERROR);
|
||||
|
||||
// PHP wrapper
|
||||
$phpwrapper = new PHPWrapper($this->session, $this->store, $importer);
|
||||
$phpwrapper = new PHPWrapper($this->session, $this->store, $importer, $this->folderid);
|
||||
|
||||
// with a folderid we are going to get content
|
||||
if($this->folderid) {
|
||||
|
@ -295,4 +295,3 @@ class ExportChangesICS implements IExportChanges{
|
|||
return false;
|
||||
}
|
||||
}
|
||||
?>
|
|
@ -197,5 +197,3 @@ class ICalParser{
|
|||
return gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -452,21 +452,7 @@ class ImportChangesICS implements IImportChanges {
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Imports a change in 'star' flag
|
||||
* This can never conflict
|
||||
*
|
||||
* @param string $id
|
||||
* @param int $flags
|
||||
*
|
||||
* @access public
|
||||
* @return boolean
|
||||
* @throws StatusException
|
||||
*/
|
||||
public function ImportMessageStarFlag($id, $flags) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Imports a move of a message. This occurs when a user moves an item to another folder
|
||||
|
@ -489,10 +475,6 @@ class ImportChangesICS implements IImportChanges {
|
|||
if (strtolower($newfolder) == strtolower(bin2hex($this->folderid)) )
|
||||
throw new StatusException(sprintf("ImportChangesICS->ImportMessageMove('%s','%s'): Error, source and destination are equal", $id, $newfolder), SYNC_MOVEITEMSSTATUS_SAMESOURCEANDDEST);
|
||||
|
||||
// check if the source message is in the current syncinterval
|
||||
if (!$this->isMessageInSyncInterval($id))
|
||||
throw new StatusException(sprintf("ImportChangesICS->ImportMessageMove('%s','%s'): Source message is outside the sync interval. Move not performed.", $id, $newfolder), SYNC_MOVEITEMSSTATUS_INVALIDSOURCEID);
|
||||
|
||||
// Get the entryid of the message we're moving
|
||||
$entryid = mapi_msgstore_entryidfromsourcekey($this->store, $this->folderid, hex2bin($id));
|
||||
if(!$entryid)
|
||||
|
@ -500,8 +482,18 @@ class ImportChangesICS implements IImportChanges {
|
|||
|
||||
//open the source message
|
||||
$srcmessage = mapi_msgstore_openentry($this->store, $entryid);
|
||||
if (!$srcmessage)
|
||||
throw new StatusException(sprintf("ImportChangesICS->ImportMessageMove('%s','%s'): Error, unable to open source message: 0x%X", $id, $newfolder, mapi_last_hresult()), SYNC_MOVEITEMSSTATUS_INVALIDSOURCEID);
|
||||
if (!$srcmessage) {
|
||||
$code = SYNC_MOVEITEMSSTATUS_INVALIDSOURCEID;
|
||||
// if we move to the trash and the source message is not found, we can also just tell the mobile that we successfully moved to avoid errors (ZP-624)
|
||||
if ($newfolder == ZPush::GetBackend()->GetWasteBasket()) {
|
||||
$code = SYNC_MOVEITEMSSTATUS_SUCCESS;
|
||||
}
|
||||
throw new StatusException(sprintf("ImportChangesICS->ImportMessageMove('%s','%s'): Error, unable to open source message: 0x%X", $id, $newfolder, mapi_last_hresult()), $code);
|
||||
}
|
||||
|
||||
// check if the source message is in the current syncinterval
|
||||
if (!$this->isMessageInSyncInterval($id))
|
||||
throw new StatusException(sprintf("ImportChangesICS->ImportMessageMove('%s','%s'): Source message is outside the sync interval. Move not performed.", $id, $newfolder), SYNC_MOVEITEMSSTATUS_INVALIDSOURCEID);
|
||||
|
||||
// get correct mapi store for the destination folder
|
||||
$dststore = ZPush::GetBackend()->GetMAPIStoreForFolderId(ZPush::GetAdditionalSyncFolderStore($newfolder), $newfolder);
|
||||
|
@ -702,5 +694,4 @@ class ImportChangesICS implements IImportChanges {
|
|||
|
||||
return $ret;
|
||||
}
|
||||
}
|
||||
?>
|
||||
}
|
|
@ -47,6 +47,8 @@
|
|||
|
||||
define("PHP_MAPI_PATH", "/usr/share/php/mapi/");
|
||||
define('MAPI_SERVER', 'file:///var/run/zarafa');
|
||||
define('SSLCERT_FILE', null);
|
||||
define('SSLCERT_PASS', null);
|
||||
|
||||
$supported_classes = array (
|
||||
"IPF.Note" => "SYNC_FOLDER_TYPE_USER_MAIL",
|
||||
|
@ -65,8 +67,8 @@ function main() {
|
|||
|
||||
function listfolders_configure() {
|
||||
|
||||
if (!isset($_SERVER["TERM"]) || !isset($_SERVER["LOGNAME"])) {
|
||||
echo "This script should not be called in a browser.\n";
|
||||
if (php_sapi_name() != "cli") {
|
||||
printf("This script should not be called in a browser. Called from: %s\n", php_sapi_name());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
@ -83,32 +85,40 @@ function listfolders_configure() {
|
|||
}
|
||||
|
||||
function listfolders_handle() {
|
||||
$shortoptions = "l:h:u:p:";
|
||||
$shortoptions = "l:h:u:p:c:";
|
||||
$options = getopt($shortoptions);
|
||||
|
||||
$mapi = MAPI_SERVER;
|
||||
$sslcert_file = SSLCERT_FILE;
|
||||
$sslcert_pass = SSLCERT_PASS;
|
||||
$user = "SYSTEM";
|
||||
$pass = "";
|
||||
|
||||
if (isset($options['h']))
|
||||
$mapi = $options['h'];
|
||||
|
||||
// accept a remote user
|
||||
if (isset($options['u']) && isset($options['p'])) {
|
||||
$user = $options['u'];
|
||||
$pass = $options['p'];
|
||||
}
|
||||
// accept a certificate and passwort for login
|
||||
else if (isset($options['c']) && isset($options['p'])) {
|
||||
$sslcert_file = $options['c'];
|
||||
$sslcert_pass = $options['p'];
|
||||
}
|
||||
|
||||
$zarafaAdmin = listfolders_zarafa_admin_setup($mapi, $user, $pass);
|
||||
$zarafaAdmin = listfolders_zarafa_admin_setup($mapi, $user, $pass, $sslcert_file, $sslcert_pass);
|
||||
if (isset($zarafaAdmin['adminStore']) && isset($options['l'])) {
|
||||
listfolders_getlist($zarafaAdmin['adminStore'], $zarafaAdmin['session'], trim($options['l']));
|
||||
}
|
||||
else {
|
||||
echo "Usage:\nlistfolders.php [actions] [options]\n\nActions: [-l username]\n\t-l username\tlist folders of user, for public folder use 'SYSTEM'\n\nGlobal options: [-h path] [[-u remoteuser] [-p password]]\n\t-h path\t\tconnect through <path>, e.g. file:///var/run/socket\n\t-u authuser\tlogin as authenticated administration user\n\t-p authpassword\tpassword of the remoteuser\n\n";
|
||||
echo "Usage:\nlistfolders.php [actions] [options]\n\nActions: [-l username]\n\t-l username\tlist folders of user, for public folder use 'SYSTEM'\n\nGlobal options: [-h path] [[-u remoteuser] [-p password]] [[-c certificate_path] [-p password]]\n\t-h path\t\tconnect through <path>, e.g. file:///var/run/socket or https://10.0.0.1:237/zarafa\n\t-u remoteuser\tlogin as authenticated administration user\n\t-c certificate\tlogin with a ssl certificate located in this location, e.g. /etc/zarafa/ssl/client.pem\n\t-p password\tpassword of the remoteuser or certificate\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
function listfolders_zarafa_admin_setup ($mapi, $user, $pass) {
|
||||
$session = @mapi_logon_zarafa($user, $pass, $mapi);
|
||||
function listfolders_zarafa_admin_setup ($mapi, $user, $pass, $sslcert_file, $sslcert_pass) {
|
||||
$session = @mapi_logon_zarafa($user, $pass, $mapi, $sslcert_file, $sslcert_pass);
|
||||
|
||||
if (!$session) {
|
||||
echo "User '$user' could not login. The script will exit. Errorcode: 0x". sprintf("%x", mapi_last_hresult()) . "\n";
|
||||
|
@ -180,5 +190,3 @@ function listfolders_getlist ($adminStore, $session, $user) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -223,4 +223,3 @@ class BaseException extends Exception
|
|||
|
||||
// @TODO getTrace and getTraceAsString
|
||||
}
|
||||
?>
|
|
@ -1942,4 +1942,3 @@
|
|||
return $a["start"] == $b["start"] ? 0 : ($a["start"] > $b["start"] ? 1 : -1 );
|
||||
}
|
||||
}
|
||||
?>
|
|
@ -394,4 +394,3 @@ class FreeBusyPublish {
|
|||
}
|
||||
|
||||
}
|
||||
?>
|
|
@ -104,4 +104,3 @@
|
|||
if (function_exists('mapi_enable_exceptions')) {
|
||||
//mapi_enable_exceptions("mapiexception");
|
||||
}
|
||||
?>
|
|
@ -3195,4 +3195,3 @@ If it is the first time this attendee has proposed a new date/time, increment th
|
|||
$this->meetingTimeInfo = $meetingTimeInfo;
|
||||
}
|
||||
}
|
||||
?>
|
|
@ -1574,4 +1574,3 @@
|
|||
.... ULONGx2 Constant: { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}.
|
||||
|
||||
*/
|
||||
?>
|
|
@ -461,4 +461,3 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
?>
|
|
@ -1033,4 +1033,3 @@
|
|||
$this->doUpdate($prefix, $prefixComplete);
|
||||
}
|
||||
}
|
||||
?>
|
|
@ -336,4 +336,3 @@ function getCalendarItems($store, $calendar, $viewstart, $viewend, $propsrequest
|
|||
// properties that the caller did not request (recurring, etc). This shouldn't be a problem though.
|
||||
return $result;
|
||||
}
|
||||
?>
|
|
@ -244,7 +244,3 @@ define('SYNC_E_UNSYNCHRONIZED', make_mapi_e(0x805));
|
|||
|
||||
define('SYNC_W_PROGRESS', make_mapi_s(0x820));
|
||||
define('SYNC_W_CLIENT_CHANGE_NEWER', make_mapi_s(0x821));
|
||||
|
||||
|
||||
|
||||
?>
|
|
@ -664,5 +664,3 @@ define('fnevTableModified' ,0x00000100);
|
|||
define('fnevStatusObjectModified' ,0x00000200);
|
||||
define('fnevReservedForMapi' ,0x40000000);
|
||||
define('fnevExtended' ,0x80000000);
|
||||
|
||||
?>
|
|
@ -70,5 +70,3 @@ define('PS_INTERNET_HEADERS', makeguid("{00020386-0000-0000-c0
|
|||
|
||||
// sk added for Z-Push
|
||||
define ('PSETID_AirSync', makeguid("{71035549-0739-4DCB-9163-00F0580DBBDF}"));
|
||||
|
||||
?>
|
|
@ -1252,5 +1252,3 @@ define('PR_ZC_CONTACT_FOLDER_NAMES' ,mapi_prop_tag(PT_MV_TSTRI
|
|||
|
||||
//Properties defined for Z-Push
|
||||
define('PR_TODO_ITEM_FLAGS' ,mapi_prop_tag(PT_LONG, 0x0E2B));
|
||||
|
||||
?>
|
|
@ -378,6 +378,7 @@ class MAPIMapping {
|
|||
"startdate" => "PT_SYSTIME:PSETID_Task:0x8104",
|
||||
"subject" => PR_SUBJECT,
|
||||
"rtf" => PR_RTF_COMPRESSED,
|
||||
"html" => PR_HTML,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -518,7 +519,8 @@ class MAPIMapping {
|
|||
"attachnum" => PR_ATTACH_NUM,
|
||||
"attachdatabin" => PR_ATTACH_DATA_BIN,
|
||||
"internetcpid" => PR_INTERNET_CPID,
|
||||
"rtf" => PR_RTF_COMPRESSED,
|
||||
"rtfinsync" => PR_RTF_IN_SYNC,
|
||||
);
|
||||
}
|
||||
}
|
||||
?>
|
||||
}
|
|
@ -12,7 +12,7 @@
|
|||
*
|
||||
* Created : 14.02.2011
|
||||
*
|
||||
* Copyright 2007 - 2013 Zarafa Deutschland GmbH
|
||||
* Copyright 2007 - 2015 Zarafa Deutschland GmbH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
|
@ -59,6 +59,7 @@ class PHPWrapper {
|
|||
private $mapiprovider;
|
||||
private $store;
|
||||
private $contentparameters;
|
||||
private $folderid;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -66,15 +67,17 @@ class PHPWrapper {
|
|||
*
|
||||
* @param ressource $session
|
||||
* @param ressource $store
|
||||
* @param IImportChanges $importer incoming changes from ICS are forwarded here
|
||||
* @param IImportChanges $importer incoming changes from ICS are forwarded here.
|
||||
* @param string $folderid the folder this wrapper was configured for.
|
||||
*
|
||||
* @access public
|
||||
* @return
|
||||
*/
|
||||
public function PHPWrapper($session, $store, $importer) {
|
||||
public function PHPWrapper($session, $store, $importer, $folderid) {
|
||||
$this->importer = &$importer;
|
||||
$this->store = $store;
|
||||
$this->mapiprovider = new MAPIProvider($session, $this->store);
|
||||
$this->folderid = $folderid;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -117,6 +120,7 @@ class PHPWrapper {
|
|||
|
||||
$mapimessage = mapi_msgstore_openentry($this->store, $entryid);
|
||||
try {
|
||||
ZLog::Write(LOGLEVEL_DEBUG, sprintf("PHPWrapper->ImportMessageChange(): Getting message from MAPIProvider, sourcekey: '%s', parentsourcekey: '%s', entryid: '%s'", bin2hex($sourcekey), bin2hex($parentsourcekey), bin2hex($entryid)));
|
||||
$message = $this->mapiprovider->GetMessage($mapimessage, $this->contentparameters);
|
||||
}
|
||||
catch (SyncObjectBrokenException $mbe) {
|
||||
|
@ -156,6 +160,13 @@ class PHPWrapper {
|
|||
* @return
|
||||
*/
|
||||
public function ImportMessageDeletion($flags, $sourcekeys) {
|
||||
$amount = count($sourcekeys);
|
||||
if ($amount > 1000) {
|
||||
throw new StatusException(sprintf("PHPWrapper->ImportMessageDeletion(): Received %d remove requests from ICS for folder '%s' (max. 1000 allowed). Triggering folder re-sync.", $amount, bin2hex($this->folderid)), SYNC_STATUS_INVALIDSYNCKEY, null, LOGLEVEL_ERROR);
|
||||
}
|
||||
else {
|
||||
ZLog::Write(LOGLEVEL_DEBUG, sprintf("PHPWrapper->ImportMessageDeletion(): Received %d remove requests from ICS", $amount));
|
||||
}
|
||||
foreach($sourcekeys as $sourcekey) {
|
||||
$this->importer->ImportMessageDeletion(bin2hex($sourcekey));
|
||||
}
|
||||
|
@ -189,16 +200,13 @@ class PHPWrapper {
|
|||
/**
|
||||
* Imports a single folder change
|
||||
*
|
||||
* @param mixed $props sourcekey of the changed folder
|
||||
* @param array $props properties of the changed folder
|
||||
*
|
||||
* @access public
|
||||
* @return
|
||||
*/
|
||||
function ImportFolderChange($props) {
|
||||
$sourcekey = $props[PR_SOURCE_KEY];
|
||||
$entryid = mapi_msgstore_entryidfromsourcekey($this->store, $sourcekey);
|
||||
$mapifolder = mapi_msgstore_openentry($this->store, $entryid);
|
||||
$folder = $this->mapiprovider->GetFolder($mapifolder);
|
||||
$folder = $this->mapiprovider->GetFolder($props);
|
||||
|
||||
// do not import folder if there is something "wrong" with it
|
||||
if ($folder === false)
|
||||
|
@ -223,6 +231,4 @@ class PHPWrapper {
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
}
|
|
@ -46,6 +46,8 @@ class MAPIProvider {
|
|||
private $store;
|
||||
private $zRFC822;
|
||||
private $addressbook;
|
||||
private $storeProps;
|
||||
private $inboxProps;
|
||||
|
||||
/**
|
||||
* Constructor of the MAPI Provider
|
||||
|
@ -277,8 +279,9 @@ class MAPIProvider {
|
|||
}
|
||||
}
|
||||
|
||||
//set attendee's status and type if they're available
|
||||
if (isset($row[PR_RECIPIENT_TRACKSTATUS]))
|
||||
//set attendee's status and type if they're available and if we are the organizer
|
||||
$storeprops = $this->getStoreProps();
|
||||
if (isset($row[PR_RECIPIENT_TRACKSTATUS]) && $messageprops[$appointmentprops["representingentryid"]] == $storeprops[PR_MAILBOX_OWNER_ENTRYID])
|
||||
$attendee->attendeestatus = $row[PR_RECIPIENT_TRACKSTATUS];
|
||||
if (isset($row[PR_RECIPIENT_TYPE]))
|
||||
$attendee->attendeetype = $row[PR_RECIPIENT_TYPE];
|
||||
|
@ -319,6 +322,11 @@ class MAPIProvider {
|
|||
$message->busystatus = fbFree;
|
||||
}
|
||||
|
||||
// If the busystatus has the value of -1, we should be interpreted as tentative (1) / ZP-581
|
||||
if (isset($message->busystatus) && $message->busystatus == -1) {
|
||||
$message->busystatus = fbTentative;
|
||||
}
|
||||
|
||||
return $message;
|
||||
}
|
||||
|
||||
|
@ -468,6 +476,12 @@ class MAPIProvider {
|
|||
if (isset($exception->busystatus) && $exception->busystatus == fbWorkingElsewhere) {
|
||||
$exception->busystatus = fbFree;
|
||||
}
|
||||
|
||||
// If the busystatus has the value of -1, we should be interpreted as tentative (1) / ZP-581
|
||||
if (isset($exception->busystatus) && $exception->busystatus == -1) {
|
||||
$exception->busystatus = fbTentative;
|
||||
}
|
||||
|
||||
array_push($syncMessage->exceptions, $exception);
|
||||
}
|
||||
|
||||
|
@ -622,15 +636,29 @@ class MAPIProvider {
|
|||
if(!isset($message->meetingrequest->sensitivity))
|
||||
$message->meetingrequest->sensitivity = 0;
|
||||
|
||||
// If the user is working from a location other than the office the busystatus should be interpreted as free.
|
||||
if (isset($message->meetingrequest->busystatus) && $message->meetingrequest->busystatus == fbWorkingElsewhere) {
|
||||
$message->meetingrequest->busystatus = fbFree;
|
||||
}
|
||||
|
||||
// If the busystatus has the value of -1, we should be interpreted as tentative (1) / ZP-581
|
||||
if (isset($message->meetingrequest->busystatus) && $message->meetingrequest->busystatus == -1) {
|
||||
$message->meetingrequest->busystatus = fbTentative;
|
||||
}
|
||||
|
||||
// if a meeting request response hasn't been processed yet,
|
||||
// do it so that the attendee status is updated on the mobile
|
||||
if(!isset($messageprops[$emailproperties["processed"]])) {
|
||||
$req = new Meetingrequest($this->store, $mapimessage, $this->session);
|
||||
if ($req->isMeetingRequestResponse()) {
|
||||
$req->processMeetingRequestResponse();
|
||||
}
|
||||
if ($req->isMeetingCancellation()) {
|
||||
$req->processMeetingCancellation();
|
||||
// check if we are not sending the MR so we can process it - ZP-581
|
||||
$cuser = ZPush::GetBackend()->GetUserDetails(ZPush::GetBackend()->GetCurrentUsername());
|
||||
if(isset($cuser["emailaddress"]) && $cuser["emailaddress"] != $fromaddr) {
|
||||
$req = new Meetingrequest($this->store, $mapimessage, $this->session);
|
||||
if ($req->isMeetingRequestResponse()) {
|
||||
$req->processMeetingRequestResponse();
|
||||
}
|
||||
if ($req->isMeetingCancellation()) {
|
||||
$req->processMeetingCancellation();
|
||||
}
|
||||
}
|
||||
}
|
||||
$message->contentclass = DEFAULT_CALENDAR_CONTENTCLASS;
|
||||
|
@ -789,18 +817,17 @@ class MAPIProvider {
|
|||
}
|
||||
|
||||
/**
|
||||
* Reads a folder object from MAPI
|
||||
* Creates a SyncFolder from MAPI properties.
|
||||
*
|
||||
* @param mixed $mapimessage
|
||||
* @param mixed $folderprops
|
||||
*
|
||||
* @access public
|
||||
* @return SyncFolder
|
||||
*/
|
||||
public function GetFolder($mapifolder) {
|
||||
public function GetFolder($folderprops) {
|
||||
$folder = new SyncFolder();
|
||||
|
||||
$folderprops = mapi_getprops($mapifolder, array(PR_DISPLAY_NAME, PR_PARENT_ENTRYID, PR_SOURCE_KEY, PR_PARENT_SOURCE_KEY, PR_ENTRYID, PR_CONTAINER_CLASS, PR_ATTR_HIDDEN));
|
||||
$storeprops = mapi_getprops($this->store, array(PR_IPM_SUBTREE_ENTRYID));
|
||||
$storeprops = $this->getStoreProps();
|
||||
|
||||
if(!isset($folderprops[PR_DISPLAY_NAME]) ||
|
||||
!isset($folderprops[PR_PARENT_ENTRYID]) ||
|
||||
|
@ -818,6 +845,12 @@ class MAPIProvider {
|
|||
return false;
|
||||
}
|
||||
|
||||
// ignore certain undesired folders, like "RSS Feeds"
|
||||
if (isset($folderprops[PR_CONTAINER_CLASS]) && $folderprops[PR_CONTAINER_CLASS] == "IPF.Note.OutlookHomepage") {
|
||||
ZLog::Write(LOGLEVEL_DEBUG, sprintf("MAPIProvider->GetFolder(): folder '%s' should not be synchronized", $folderprops[PR_DISPLAY_NAME]));
|
||||
return false;
|
||||
}
|
||||
|
||||
$folder->serverid = bin2hex($folderprops[PR_SOURCE_KEY]);
|
||||
if($folderprops[PR_PARENT_ENTRYID] == $storeprops[PR_IPM_SUBTREE_ENTRYID])
|
||||
$folder->parentid = "0";
|
||||
|
@ -840,9 +873,8 @@ class MAPIProvider {
|
|||
* @return long
|
||||
*/
|
||||
public function GetFolderType($entryid, $class = false) {
|
||||
$storeprops = mapi_getprops($this->store, array(PR_IPM_OUTBOX_ENTRYID, PR_IPM_WASTEBASKET_ENTRYID, PR_IPM_SENTMAIL_ENTRYID));
|
||||
$inbox = mapi_msgstore_getreceivefolder($this->store);
|
||||
$inboxprops = mapi_getprops($inbox, array(PR_ENTRYID, PR_IPM_DRAFTS_ENTRYID, PR_IPM_TASK_ENTRYID, PR_IPM_APPOINTMENT_ENTRYID, PR_IPM_CONTACT_ENTRYID, PR_IPM_NOTE_ENTRYID, PR_IPM_JOURNAL_ENTRYID));
|
||||
$storeprops = $this->getStoreProps();
|
||||
$inboxprops = $this->getInboxProps();
|
||||
|
||||
if($entryid == $inboxprops[PR_ENTRYID])
|
||||
return SYNC_FOLDER_TYPE_INBOX;
|
||||
|
@ -1255,6 +1287,7 @@ class MAPIProvider {
|
|||
$representingprops = $this->getProps($mapimessage, $p);
|
||||
|
||||
if (!isset($representingprops[$appointmentprops["representingentryid"]])) {
|
||||
// TODO use getStoreProps
|
||||
$storeProps = mapi_getprops($this->store, array(PR_MAILBOX_OWNER_ENTRYID));
|
||||
$props[$appointmentprops["representingentryid"]] = $storeProps[PR_MAILBOX_OWNER_ENTRYID];
|
||||
$displayname = $this->getFullnameFromEntryID($storeProps[PR_MAILBOX_OWNER_ENTRYID]);
|
||||
|
@ -1518,9 +1551,10 @@ class MAPIProvider {
|
|||
// "start" and "end" are in GMT when passing to class.recurrence
|
||||
// set recurrence start here because it's calculated differently for tasks and appointments
|
||||
$recur["start"] = $task->recurrence->start;
|
||||
$recur["regen"] = $task->regenerate;
|
||||
$recur["regen"] = (isset($task->recurrence->regenerate) && $task->recurrence->regenerate) ? 1 : 0;
|
||||
//Also add dates to $recur
|
||||
$recur["duedate"] = $task->duedate;
|
||||
$recur["complete"] = (isset($task->complete) && $task->complete) ? 1 : 0;
|
||||
$recurrence->setRecurrence($recur);
|
||||
}
|
||||
|
||||
|
@ -2607,6 +2641,33 @@ class MAPIProvider {
|
|||
}
|
||||
return $this->addressbook;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
/**
|
||||
* Gets the required store properties.
|
||||
*
|
||||
* @access private
|
||||
* @return array
|
||||
*/
|
||||
private function getStoreProps() {
|
||||
if (!isset($this->storeProps) || empty($this->storeProps)) {
|
||||
ZLog::Write(LOGLEVEL_DEBUG, "MAPIProvider->getStoreProps(): Getting store properties.");
|
||||
$this->storeProps = mapi_getprops($this->store, array(PR_IPM_SUBTREE_ENTRYID, PR_IPM_OUTBOX_ENTRYID, PR_IPM_WASTEBASKET_ENTRYID, PR_IPM_SENTMAIL_ENTRYID, PR_ENTRYID, PR_IPM_PUBLIC_FOLDERS_ENTRYID, PR_IPM_FAVORITES_ENTRYID, PR_MAILBOX_OWNER_ENTRYID));
|
||||
}
|
||||
return $this->storeProps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the required inbox properties.
|
||||
*
|
||||
* @access private
|
||||
* @return array
|
||||
*/
|
||||
private function getInboxProps() {
|
||||
if (!isset($this->inboxProps) || empty($this->inboxProps)) {
|
||||
ZLog::Write(LOGLEVEL_DEBUG, "MAPIProvider->getInboxProps(): Getting inbox properties.");
|
||||
$inbox = mapi_msgstore_getreceivefolder($this->store);
|
||||
$this->inboxProps = mapi_getprops($inbox, array(PR_ENTRYID, PR_IPM_DRAFTS_ENTRYID, PR_IPM_TASK_ENTRYID, PR_IPM_APPOINTMENT_ENTRYID, PR_IPM_CONTACT_ENTRYID, PR_IPM_NOTE_ENTRYID, PR_IPM_JOURNAL_ENTRYID));
|
||||
}
|
||||
return $this->inboxProps;
|
||||
}
|
||||
}
|
|
@ -143,6 +143,4 @@ class MAPIStreamWrapper {
|
|||
}
|
||||
}
|
||||
|
||||
stream_wrapper_register(MAPIStreamWrapper::PROTOCOL, "MAPIStreamWrapper")
|
||||
|
||||
?>
|
||||
stream_wrapper_register(MAPIStreamWrapper::PROTOCOL, "MAPIStreamWrapper");
|
||||
|
|
|
@ -482,6 +482,104 @@ class MAPIUtils {
|
|||
);
|
||||
}
|
||||
|
||||
}
|
||||
/**
|
||||
* Calculates the native body type of a message using available properties. Refer to oxbbody.
|
||||
*
|
||||
* @param array $messageprops
|
||||
*
|
||||
* @access public
|
||||
* @return int
|
||||
*/
|
||||
public static function GetNativeBodyType($messageprops) {
|
||||
//check if the properties are set and get the error code if needed
|
||||
if (!isset($messageprops[PR_BODY])) $messageprops[PR_BODY] = self::getError(PR_BODY, $messageprops);
|
||||
if (!isset($messageprops[PR_RTF_COMPRESSED])) $messageprops[PR_RTF_COMPRESSED] = self::getError(PR_RTF_COMPRESSED, $messageprops);
|
||||
if (!isset($messageprops[PR_HTML])) $messageprops[PR_HTML] = self::getError(PR_HTML, $messageprops);
|
||||
if (!isset($messageprops[PR_RTF_IN_SYNC])) $messageprops[PR_RTF_IN_SYNC] = self::getError(PR_RTF_IN_SYNC, $messageprops);
|
||||
|
||||
?>
|
||||
if ( // 1
|
||||
($messageprops[PR_BODY] == MAPI_E_NOT_FOUND) &&
|
||||
($messageprops[PR_RTF_COMPRESSED] == MAPI_E_NOT_FOUND) &&
|
||||
($messageprops[PR_HTML] == MAPI_E_NOT_FOUND))
|
||||
return SYNC_BODYPREFERENCE_PLAIN;
|
||||
elseif ( // 2
|
||||
($messageprops[PR_BODY] == MAPI_E_NOT_ENOUGH_MEMORY) &&
|
||||
($messageprops[PR_RTF_COMPRESSED] == MAPI_E_NOT_FOUND) &&
|
||||
($messageprops[PR_HTML] == MAPI_E_NOT_FOUND))
|
||||
return SYNC_BODYPREFERENCE_PLAIN;
|
||||
elseif ( // 3
|
||||
($messageprops[PR_BODY] == MAPI_E_NOT_ENOUGH_MEMORY) &&
|
||||
($messageprops[PR_RTF_COMPRESSED] == MAPI_E_NOT_ENOUGH_MEMORY) &&
|
||||
($messageprops[PR_HTML] == MAPI_E_NOT_FOUND))
|
||||
return SYNC_BODYPREFERENCE_RTF;
|
||||
elseif ( // 4
|
||||
($messageprops[PR_BODY] == MAPI_E_NOT_ENOUGH_MEMORY) &&
|
||||
($messageprops[PR_RTF_COMPRESSED] == MAPI_E_NOT_ENOUGH_MEMORY) &&
|
||||
($messageprops[PR_HTML] == MAPI_E_NOT_ENOUGH_MEMORY) &&
|
||||
($messageprops[PR_RTF_IN_SYNC]))
|
||||
return SYNC_BODYPREFERENCE_RTF;
|
||||
elseif ( // 5
|
||||
($messageprops[PR_BODY] == MAPI_E_NOT_ENOUGH_MEMORY) &&
|
||||
($messageprops[PR_RTF_COMPRESSED] == MAPI_E_NOT_ENOUGH_MEMORY) &&
|
||||
($messageprops[PR_HTML] == MAPI_E_NOT_ENOUGH_MEMORY) &&
|
||||
(!$messageprops[PR_RTF_IN_SYNC]))
|
||||
return SYNC_BODYPREFERENCE_HTML;
|
||||
elseif ( // 6
|
||||
($messageprops[PR_RTF_COMPRESSED] != MAPI_E_NOT_FOUND || $messageprops[PR_RTF_COMPRESSED] == MAPI_E_NOT_ENOUGH_MEMORY) &&
|
||||
($messageprops[PR_HTML] != MAPI_E_NOT_FOUND || $messageprops[PR_HTML] == MAPI_E_NOT_ENOUGH_MEMORY) &&
|
||||
($messageprops[PR_RTF_IN_SYNC]))
|
||||
return SYNC_BODYPREFERENCE_RTF;
|
||||
elseif ( // 7
|
||||
($messageprops[PR_RTF_COMPRESSED] != MAPI_E_NOT_FOUND || $messageprops[PR_RTF_COMPRESSED] == MAPI_E_NOT_ENOUGH_MEMORY) &&
|
||||
($messageprops[PR_HTML] != MAPI_E_NOT_FOUND || $messageprops[PR_HTML] == MAPI_E_NOT_ENOUGH_MEMORY) &&
|
||||
(!$messageprops[PR_RTF_IN_SYNC]))
|
||||
return SYNC_BODYPREFERENCE_HTML;
|
||||
elseif ( // 8
|
||||
($messageprops[PR_BODY] != MAPI_E_NOT_FOUND || $messageprops[PR_BODY] == MAPI_E_NOT_ENOUGH_MEMORY) &&
|
||||
($messageprops[PR_RTF_COMPRESSED] != MAPI_E_NOT_FOUND || $messageprops[PR_RTF_COMPRESSED] == MAPI_E_NOT_ENOUGH_MEMORY) &&
|
||||
($messageprops[PR_RTF_IN_SYNC]))
|
||||
return SYNC_BODYPREFERENCE_RTF;
|
||||
elseif ( // 9.1
|
||||
($messageprops[PR_BODY] != MAPI_E_NOT_FOUND || $messageprops[PR_BODY] == MAPI_E_NOT_ENOUGH_MEMORY) &&
|
||||
($messageprops[PR_RTF_COMPRESSED] != MAPI_E_NOT_FOUND || $messageprops[PR_RTF_COMPRESSED] == MAPI_E_NOT_ENOUGH_MEMORY) &&
|
||||
(!$messageprops[PR_RTF_IN_SYNC]))
|
||||
return SYNC_BODYPREFERENCE_PLAIN;
|
||||
elseif ( // 9.2
|
||||
($messageprops[PR_RTF_COMPRESSED] != MAPI_E_NOT_FOUND || $messageprops[PR_RTF_COMPRESSED] == MAPI_E_NOT_ENOUGH_MEMORY) &&
|
||||
($messageprops[PR_BODY] == MAPI_E_NOT_FOUND) &&
|
||||
($messageprops[PR_HTML] == MAPI_E_NOT_FOUND))
|
||||
return SYNC_BODYPREFERENCE_RTF;
|
||||
elseif ( // 9.3
|
||||
($messageprops[PR_BODY] != MAPI_E_NOT_FOUND || $messageprops[PR_BODY] == MAPI_E_NOT_ENOUGH_MEMORY) &&
|
||||
($messageprops[PR_RTF_COMPRESSED] == MAPI_E_NOT_FOUND) &&
|
||||
($messageprops[PR_HTML] == MAPI_E_NOT_FOUND))
|
||||
return SYNC_BODYPREFERENCE_PLAIN;
|
||||
elseif ( // 9.4
|
||||
($messageprops[PR_HTML] != MAPI_E_NOT_FOUND || $messageprops[PR_HTML] == MAPI_E_NOT_ENOUGH_MEMORY) &&
|
||||
($messageprops[PR_BODY] == MAPI_E_NOT_FOUND) &&
|
||||
($messageprops[PR_RTF_COMPRESSED] == MAPI_E_NOT_FOUND))
|
||||
return SYNC_BODYPREFERENCE_HTML;
|
||||
else // 10
|
||||
return SYNC_BODYPREFERENCE_PLAIN;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the error code for a given property. Helper for getNativeBodyType function.
|
||||
*
|
||||
* @param int $tag
|
||||
* @param array $messageprops
|
||||
*
|
||||
* @access private
|
||||
* @return int (MAPI_ERROR_CODE)
|
||||
*/
|
||||
private static function getError($tag, $messageprops) {
|
||||
$prBodyError = mapi_prop_tag(PT_ERROR, mapi_prop_id($tag));
|
||||
if(isset($messageprops[$prBodyError]) && mapi_is_error($messageprops[$prBodyError])) {
|
||||
if($messageprops[$prBodyError] == MAPI_E_NOT_ENOUGH_MEMORY_32BIT ||
|
||||
$messageprops[$prBodyError] == MAPI_E_NOT_ENOUGH_MEMORY_64BIT) {
|
||||
return MAPI_E_NOT_ENOUGH_MEMORY;
|
||||
}
|
||||
}
|
||||
return MAPI_E_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -718,4 +718,3 @@ class TNEFParser {
|
|||
return NOERROR;
|
||||
}
|
||||
}
|
||||
?>
|
|
@ -164,7 +164,15 @@ class BackendZarafa implements IBackend, ISearchProvider {
|
|||
try {
|
||||
// check if notifications are available in php-mapi
|
||||
if(function_exists('mapi_feature') && mapi_feature('LOGONFLAGS')) {
|
||||
$this->session = @mapi_logon_zarafa($user, $pass, MAPI_SERVER, null, null, 0);
|
||||
// send Z-Push version and user agent to ZCP - ZP-589
|
||||
if (Utils::CheckMapiExtVersion('7.2.0')) {
|
||||
$zpush_version = 'Z-Push_' . @constant('ZPUSH_VERSION');
|
||||
$user_agent = $_SERVER['HTTP_USER_AGENT'];
|
||||
$this->session = @mapi_logon_zarafa($user, $pass, MAPI_SERVER, null, null, 0, $zpush_version, $user_agent);
|
||||
}
|
||||
else {
|
||||
$this->session = @mapi_logon_zarafa($user, $pass, MAPI_SERVER, null, null, 0);
|
||||
}
|
||||
$this->notifications = true;
|
||||
}
|
||||
// old fashioned session
|
||||
|
@ -453,18 +461,14 @@ class BackendZarafa implements IBackend, ISearchProvider {
|
|||
// @see http://jira.zarafa.com/browse/ZP-68
|
||||
$meetingRequestProps = MAPIMapping::GetMeetingRequestProperties();
|
||||
$meetingRequestProps = getPropIdsFromStrings($this->store, $meetingRequestProps);
|
||||
$props = mapi_getprops($mapimessage, array(PR_MESSAGE_CLASS, $meetingRequestProps["goidtag"], $sendMailProps["internetcpid"]));
|
||||
$props = mapi_getprops($mapimessage, array(PR_MESSAGE_CLASS, $meetingRequestProps["goidtag"], $sendMailProps["internetcpid"], $sendMailProps["body"], $sendMailProps["html"], $sendMailProps["rtf"], $sendMailProps["rtfinsync"]));
|
||||
|
||||
// Convert sent message's body to UTF-8.
|
||||
// @see http://jira.zarafa.com/browse/ZP-505
|
||||
if (isset($props[$sendMailProps["internetcpid"]]) && $props[$sendMailProps["internetcpid"]] != INTERNET_CPID_UTF8) {
|
||||
ZLog::Write(LOGLEVEL_DEBUG, sprintf("Sent email cpid is not unicode (%d). Set it to unicode and convert email body.", $props[$sendMailProps["internetcpid"]]));
|
||||
// Convert sent message's body to UTF-8 if it was a HTML message.
|
||||
// @see http://jira.zarafa.com/browse/ZP-505 and http://jira.zarafa.com/browse/ZP-555
|
||||
if (isset($props[$sendMailProps["internetcpid"]]) && $props[$sendMailProps["internetcpid"]] != INTERNET_CPID_UTF8 && MAPIUtils::GetNativeBodyType($props) == SYNC_BODYPREFERENCE_HTML) {
|
||||
ZLog::Write(LOGLEVEL_DEBUG, sprintf("Sent email cpid is not unicode (%d). Set it to unicode and convert email html body.", $props[$sendMailProps["internetcpid"]]));
|
||||
$mapiprops[$sendMailProps["internetcpid"]] = INTERNET_CPID_UTF8;
|
||||
|
||||
$body = MAPIUtils::readPropStream($mapimessage, PR_BODY);
|
||||
$body = Utils::ConvertCodepageStringToUtf8($props[$sendMailProps["internetcpid"]], $body);
|
||||
$mapiprops[$sendMailProps["body"]] = $body;
|
||||
|
||||
$bodyHtml = MAPIUtils::readPropStream($mapimessage, PR_HTML);
|
||||
$bodyHtml = Utils::ConvertCodepageStringToUtf8($props[$sendMailProps["internetcpid"]], $bodyHtml);
|
||||
$mapiprops[$sendMailProps["html"]] = $bodyHtml;
|
||||
|
@ -968,9 +972,9 @@ class BackendZarafa implements IBackend, ISearchProvider {
|
|||
* @throws StatusException
|
||||
*/
|
||||
public function GetGALSearchResults($searchquery, $searchrange){
|
||||
// only return users from who the displayName or the username starts with $name
|
||||
// only return users whose displayName or the username starts with $name
|
||||
//TODO: use PR_ANR for this restriction instead of PR_DISPLAY_NAME and PR_ACCOUNT
|
||||
$addrbook = mapi_openaddressbook($this->session);
|
||||
$addrbook = $this->getAddressbook();
|
||||
if ($addrbook)
|
||||
$ab_entryid = mapi_ab_getdefaultdir($addrbook);
|
||||
if ($ab_entryid)
|
||||
|
@ -1003,12 +1007,16 @@ class BackendZarafa implements IBackend, ISearchProvider {
|
|||
$querycnt = mapi_table_getrowcount($table);
|
||||
//do not return more results as requested in range
|
||||
$querylimit = (($rangeend + 1) < $querycnt) ? ($rangeend + 1) : $querycnt;
|
||||
$items['range'] = ($querylimit > 0) ? $rangestart.'-'.($querylimit - 1) : '0-0';
|
||||
$items['searchtotal'] = $querycnt;
|
||||
|
||||
if ($querycnt > 0)
|
||||
$abentries = mapi_table_queryrows($table, array(PR_ACCOUNT, PR_DISPLAY_NAME, PR_SMTP_ADDRESS, PR_BUSINESS_TELEPHONE_NUMBER, PR_GIVEN_NAME, PR_SURNAME, PR_MOBILE_TELEPHONE_NUMBER, PR_HOME_TELEPHONE_NUMBER, PR_TITLE, PR_COMPANY_NAME, PR_OFFICE_LOCATION), $rangestart, $querylimit);
|
||||
|
||||
for ($i = 0; $i < $querylimit; $i++) {
|
||||
if (!isset($abentries[$i][PR_SMTP_ADDRESS])) {
|
||||
ZLog::Write(LOGLEVEL_WARN, sprintf("The GAL entry '%s' does not have an email address and will be ignored.", w2u($abentries[$i][PR_DISPLAY_NAME])));
|
||||
continue;
|
||||
}
|
||||
|
||||
$items[$i][SYNC_GAL_DISPLAYNAME] = w2u($abentries[$i][PR_DISPLAY_NAME]);
|
||||
|
||||
if (strlen(trim($items[$i][SYNC_GAL_DISPLAYNAME])) == 0)
|
||||
|
@ -1047,6 +1055,9 @@ class BackendZarafa implements IBackend, ISearchProvider {
|
|||
if (isset($abentries[$i][PR_OFFICE_LOCATION]))
|
||||
$items[$i][SYNC_GAL_OFFICE] = w2u($abentries[$i][PR_OFFICE_LOCATION]);
|
||||
}
|
||||
$nrResults = count($items);
|
||||
$items['range'] = ($nrResults > 0) ? $rangestart.'-'.($nrResults - 1) : '0-0';
|
||||
$items['searchtotal'] = $nrResults;
|
||||
return $items;
|
||||
}
|
||||
|
||||
|
@ -1195,12 +1206,21 @@ class BackendZarafa implements IBackend, ISearchProvider {
|
|||
*/
|
||||
public function GetUserDetails($username) {
|
||||
ZLog::Write(LOGLEVEL_WBXML, sprintf("ZarafaBackend->GetUserDetails for '%s'.", $username));
|
||||
$zarafauserinfo = @mapi_zarafa_getuser_by_name($this->defaultstore, $username);
|
||||
$zarafauserinfo = @mapi_zarafa_getuser_by_name($this->store, $username);
|
||||
$userDetails['emailaddress'] = (isset($zarafauserinfo['emailaddress']) && $zarafauserinfo['emailaddress']) ? $zarafauserinfo['emailaddress'] : false;
|
||||
$userDetails['fullname'] = (isset($zarafauserinfo['fullname']) && $zarafauserinfo['fullname']) ? $zarafauserinfo['fullname'] : false;
|
||||
return $userDetails;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the username of the currently active user
|
||||
*
|
||||
* @access public
|
||||
* @return String
|
||||
*/
|
||||
public function GetCurrentUsername() {
|
||||
return $this->storeName;
|
||||
}
|
||||
|
||||
/**----------------------------------------------------------------------------------------------------------
|
||||
* Private methods
|
||||
|
@ -1880,5 +1900,3 @@ class BackendZarafa implements IBackend, ISearchProvider {
|
|||
* DEPRECATED legacy class
|
||||
*/
|
||||
class BackendICS extends BackendZarafa {}
|
||||
|
||||
?>
|
6
sources/composer.json
Normal file
6
sources/composer.json
Normal file
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"autoload": {
|
||||
"classmap": ["autodiscover/", "include/", "lib/"],
|
||||
"files": ["version.php", "lib/core/zpush-utils.php", "lib/core/zpushdefs.php", "lib/utils/compat.php"]
|
||||
}
|
||||
}
|
|
@ -48,11 +48,15 @@
|
|||
define('TIMEZONE', '');
|
||||
|
||||
// Defines the base path on the server
|
||||
define('BASE_PATH', dirname($_SERVER['SCRIPT_FILENAME']). '/');
|
||||
define('BASE_PATH', dirname(__FILE__) . '/');
|
||||
|
||||
// Try to set unlimited timeout
|
||||
define('SCRIPT_TIMEOUT', 0);
|
||||
|
||||
// Your PHP could have a bug when base64 encoding: https://bugs.php.net/bug.php?id=68532
|
||||
// NOTE: Run "php testing/testing-bug68532fixed.php" to know what value put here
|
||||
define('BUG68532FIXED', true);
|
||||
|
||||
// When accessing through a proxy, the "X-Forwarded-For" header contains the original remote IP
|
||||
define('USE_X_FORWARDED_FOR_HEADER', false);
|
||||
|
||||
|
@ -60,6 +64,10 @@
|
|||
// This setting specifies the owner parameter in the certificate to look at.
|
||||
define("CERTIFICATE_OWNER_PARAMETER", "SSL_CLIENT_S_DN_CN");
|
||||
|
||||
// Location of the trusted CA, e.g. '/etc/ssl/certs/EmailCA.pem'
|
||||
// Uncomment and modify the following line if the validation of the certificates fails.
|
||||
// define('CAINFO', '/etc/ssl/certs/EmailCA.pem');
|
||||
|
||||
/*
|
||||
* Whether to use the complete email address as a login name
|
||||
* (e.g. user@company.com) or the username only (user).
|
||||
|
@ -68,7 +76,7 @@
|
|||
* false - use the username only (default).
|
||||
* true - use the complete email address.
|
||||
*/
|
||||
define('USE_FULLEMAIL_FOR_LOGIN', false);
|
||||
define('USE_FULLEMAIL_FOR_LOGIN', true);
|
||||
|
||||
/**********************************************************************************
|
||||
* Device pre-authorization. Useful when using Z-Push as a standalone product.
|
||||
|
@ -153,9 +161,18 @@
|
|||
define('LOGUSERLEVEL', LOGLEVEL_DEVICEID);
|
||||
$specialLogUsers = array();
|
||||
|
||||
// Location of the trusted CA, e.g. '/etc/ssl/certs/EmailCA.pem'
|
||||
// Uncomment and modify the following line if the validation of the certificates fails.
|
||||
// define('CAINFO', '/etc/ssl/certs/EmailCA.pem');
|
||||
// If you want to disable log to file, and log to syslog instead
|
||||
define('LOG_SYSLOG_ENABLED', false);
|
||||
// false will log to local syslog, otherwise put the remote syslog IP here
|
||||
define('LOG_SYSLOG_HOST', false);
|
||||
// Syslog port
|
||||
define('LOG_SYSLOG_PORT', 514);
|
||||
// Program showed in the syslog. Useful if you have more than one instance login to the same syslog
|
||||
define('LOG_SYSLOG_PROGRAM', '[z-push]');
|
||||
|
||||
|
||||
define('LOG_MEMORY_PROFILER', true);
|
||||
define('LOG_MEMORY_PROFILER_FILE', '/var/log/z-push/memory_profile');
|
||||
|
||||
/**********************************************************************************
|
||||
* Mobile settings
|
||||
|
@ -238,8 +255,8 @@
|
|||
// in the semantic sanity checks and contacts with larger photos are not synchronized.
|
||||
// This limitation is not being followed by the ActiveSync clients which set much bigger
|
||||
// contact photos. You can override the default value of the max photo size.
|
||||
// default: 49152 - 48 KB default max photo size in bytes
|
||||
define('SYNC_CONTACTS_MAXPICTURESIZE', 49152);
|
||||
// default: 5242880 - 5 MB default max photo size in bytes
|
||||
define('SYNC_CONTACTS_MAXPICTURESIZE', 5242880);
|
||||
|
||||
// Over the WebserviceUsers command it is possible to retrieve a list of all
|
||||
// known devices and users on this Z-Push system. The authenticated user needs to have
|
||||
|
@ -261,6 +278,28 @@
|
|||
// the backend data provider
|
||||
define('BACKEND_PROVIDER', '');
|
||||
|
||||
// top collector backend class name
|
||||
// Default is: TopCollector
|
||||
// Options: ["TopCollector", "TopCollectorRedis"]
|
||||
define('TOP_COLLECTOR_BACKEND', 'TopCollector');
|
||||
|
||||
// ping tracking backend class name
|
||||
// Default is: PingTracking
|
||||
// Options: ["PingTracking", "PingTrackingRedis"]
|
||||
define('PING_TRACKING_BACKEND', 'PingTracking');
|
||||
|
||||
// loop detection backend class name
|
||||
// Default is: LoopDetection
|
||||
// Options: ["LoopDetection", "LoopDetectionRedis"]
|
||||
define('LOOP_DETECTION_BACKEND', 'LoopDetection');
|
||||
|
||||
// If using the Redis backends (for top, ping and lookp) make sure to set this values as necessary
|
||||
define('IPC_REDIS_IP', '127.0.0.1');
|
||||
define('IPC_REDIS_PORT', 6379);
|
||||
// Database name/index in Redis: 0 by default
|
||||
// NOTE: this database must be exclusive for z-push, since its content will be ERASED. You are warned.
|
||||
define('IPC_REDIS_DATABASE', 0);
|
||||
|
||||
/**********************************************************************************
|
||||
* Search provider settings
|
||||
*
|
||||
|
@ -328,5 +367,3 @@
|
|||
),
|
||||
*/
|
||||
);
|
||||
|
||||
?>
|
103
sources/docker/README.md
Normal file
103
sources/docker/README.md
Normal file
|
@ -0,0 +1,103 @@
|
|||
# Docker Images
|
||||
|
||||
You can run a Z-Push server using Docker containers. That is really usefull for developing, but it also can be used in production servers.
|
||||
|
||||
|
||||
Here are the basic instructions for a Nginx+PHP-FPM deployment. Feel free to contribute your Apache or other server approach.
|
||||
|
||||
|
||||
## Using Docker Composer (In progress)
|
||||
|
||||
|
||||
### Create and build basic images
|
||||
|
||||
docker-compose -f basic.yml up
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## Manual method
|
||||
|
||||
|
||||
### Build a PHP-FPM image
|
||||
|
||||
cd php-fpm
|
||||
docker build -t fmbiete/centos_zpush_php_fpm .
|
||||
|
||||
|
||||
### Build a NGINX image
|
||||
|
||||
cd nginx
|
||||
docker build -t fmbiete/centos_zpush_nginx .
|
||||
|
||||
**NOTE**: this includes a SSL self-signed certificate (2048 bytes - valid until 2025), but it's intended only for development or testing uses. In production replace it with a real one.
|
||||
|
||||
|
||||
### Create MariaDB container (optional for SQLStateMachine)
|
||||
|
||||
docker run --name zpush_mariadb -e MYSQL_ROOT_PASSWORD=root_password -e MYSQL_USER=user_name -e MYSQL_PASSWORD=user_password -e MYSQL_DATABASE=database -v mariadb_lib:/var/lib/mysql -p3306:3306 -d fbiete/centos_epel_mariadb:10
|
||||
|
||||
**TODO**: Replace *mariadb_lib* with the full path when you will store the database files
|
||||
**TODO**: If using selinux remember to change the context type for *mariadb_lib*
|
||||
**TODO**: Replace *root_password*, *user_name*, *user_password*, *database* with the right values
|
||||
|
||||
#### Load database schema
|
||||
|
||||
mysql -u root -proot_password database -h 127.0.0.1 < sql/mysql.sql
|
||||
|
||||
|
||||
### Create Redis container (optional for TopCollectorRedis, LoopDetectionRedis or PingTrackingRedis)
|
||||
|
||||
docker run --name zpush_redis -v redis_data:/data -p 6379:6379 -d fbiete/centos_epel_redis:2.8
|
||||
|
||||
**TODO**: Replace *redis_data* with the full path when you will store the database files
|
||||
**TODO**: If using selinux remember to change the context type for *redis_data*
|
||||
|
||||
### Create PHP-FPM container
|
||||
|
||||
docker run -d --name zpush_php_fpm -v zpush_repo:/var/www/z-push fmbiete/centos_zpush_php_fpm
|
||||
|
||||
#### With MariaDB
|
||||
|
||||
docker run -d --name zpush_php_fpm -v zpush_repo:/var/www/z-push --link zpush_mariadb:zpushmariadb fmbiete/centos_zpush_php_fpm
|
||||
|
||||
#### With Redis
|
||||
|
||||
docker run -d --name zpush_php_fpm -v zpush_repo:/var/www/z-push --link zpush_redis:zpushredis fmbiete/centos_zpush_php_fpm
|
||||
|
||||
**TODO**: Replace *zpush_repo* with the full path to Z-Push code
|
||||
**TODO**: Remember to zpushmariadb and zpushredis as server name in the config for MariaDB and Redis
|
||||
|
||||
|
||||
### Create NGINX container
|
||||
|
||||
docker run -d --name zpush_nginx -v zpush_repo:/var/www/z-push --link zpush_php_fpm:zpushphpfpm -p 443:443 fmbiete/centos_zpush_nginx
|
||||
|
||||
**TODO**: Replace *zpush_repo* with the full path to Z-Push code
|
||||
|
||||
|
||||
### Stop containers
|
||||
|
||||
docker stop zpush_nginx
|
||||
docker stop zpush_php_fpm
|
||||
docker stop zpush_mariadb
|
||||
docker stop zpush_redis
|
||||
|
||||
|
||||
### Start containers
|
||||
|
||||
docker start zpush_mariadb
|
||||
docker start zpush_redis
|
||||
docker start zpush_php_fpm
|
||||
docker start zpush_nginx
|
||||
|
||||
|
||||
### Remove containers
|
||||
|
||||
docker rm zpush_nginx
|
||||
docker rm zpush_php_fpm
|
||||
docker rm zpush_mariadb
|
||||
docker rm zpush_redis
|
||||
|
||||
**NOTE**: The order of the containers in the operation is important
|
13
sources/docker/basic.yml
Normal file
13
sources/docker/basic.yml
Normal file
|
@ -0,0 +1,13 @@
|
|||
phpfpm:
|
||||
build: php-fpm/
|
||||
volumes:
|
||||
- ..:/var/www/z-push:Z
|
||||
nginx:
|
||||
build: nginx/
|
||||
volumes_from:
|
||||
- phpfpm
|
||||
links:
|
||||
- phpfpm:zpushphpfpm
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
16
sources/docker/nginx/Dockerfile
Normal file
16
sources/docker/nginx/Dockerfile
Normal file
|
@ -0,0 +1,16 @@
|
|||
FROM fbiete/centos_epel_nginx:1.8
|
||||
MAINTAINER Francisco Miguel Biete <fbiete@gmail.com>
|
||||
|
||||
RUN mkdir /var/www /var/www/z-push /etc/ssl/nginx \
|
||||
&& chown -R nginx:nginx /var/www
|
||||
|
||||
COPY localhost.crt /etc/ssl/nginx/localhost.crt
|
||||
COPY localhost.key /etc/ssl/nginx/localhost.key
|
||||
|
||||
COPY nginx.conf /etc/nginx/
|
||||
|
||||
VOLUME /var/www/z-push
|
||||
|
||||
CMD [ "nginx", "-g", "daemon off;" ]
|
||||
|
||||
|
21
sources/docker/nginx/localhost.crt
Normal file
21
sources/docker/nginx/localhost.crt
Normal file
|
@ -0,0 +1,21 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIDfzCCAmegAwIBAgIJAMNks+T7RrPhMA0GCSqGSIb3DQEBCwUAMFYxCzAJBgNV
|
||||
BAYTAlhYMRUwEwYDVQQHDAxEZWZhdWx0IENpdHkxHDAaBgNVBAoME0RlZmF1bHQg
|
||||
Q29tcGFueSBMdGQxEjAQBgNVBAMMCWxvY2FsaG9zdDAeFw0xNTAzMTYwNzQwMzZa
|
||||
Fw0yNTAzMTMwNzQwMzZaMFYxCzAJBgNVBAYTAlhYMRUwEwYDVQQHDAxEZWZhdWx0
|
||||
IENpdHkxHDAaBgNVBAoME0RlZmF1bHQgQ29tcGFueSBMdGQxEjAQBgNVBAMMCWxv
|
||||
Y2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALhw96+bbz0I
|
||||
5tPNAUJo/TG3Qi8RzkHyeGeg+dbMckS2Y3gcaa4E8nsnuKisbmHZu6Zgc7P8sr9d
|
||||
V6qTsz07aJuy5pdt3+y9oiHPd05EZ4aZSXbfdGLAwr94D6R3AI6zv6lA+cCAHIIu
|
||||
A4tgOmjtykre632dDDVLyDyxVTekn28q6ag+6vDnj9gyABsvER7WsJpi1Af6HxH2
|
||||
/tM1EtCKam5SNVy9+lQs3/pXk8r8kKvKVyrewhTzy4F8IRVi0vXtcW7wtkDwO1Ti
|
||||
+CN1C1ETQZ2jfTk7Z9xGaFbS5cIEbHH3AmBgJjT396pUBQEqQVHBsHxvmhFhKMBi
|
||||
ejvFbTYFz8cCAwEAAaNQME4wHQYDVR0OBBYEFECo2oRuFvk9sUOwRzZ+BeH48YJR
|
||||
MB8GA1UdIwQYMBaAFECo2oRuFvk9sUOwRzZ+BeH48YJRMAwGA1UdEwQFMAMBAf8w
|
||||
DQYJKoZIhvcNAQELBQADggEBAK5ZATJ3Oh+0bXXdPMSTCZDgsGYpm5/BrUiAbqXX
|
||||
mMRWyx6nUF6QqDu6Fku+Jgo0RwhXz7VfwI1JNXWvDsoEnjCbWJ2+njH08qBn9Xex
|
||||
wtxL+kwnjXVeZgskUa9sAP+nr2gyzhjyRFjx1W3gZQeJ9VY2pDKLpW2NTkUOEhOH
|
||||
YzLSUzVlXdQUauiYglzqip7dUId5VeDXHC8merB7Iq8h7QxD0WVHyjlgSjWEH8Gq
|
||||
MDaY+n6CyPXkmusNJlQoWB/CJcLfr3tSVvaqmZ49K3OZph3DCKiGnSqqFi5OqKLg
|
||||
YkcculYQGwfUkqZPqTb++MTsKkuaQPk4UDbPYAYhHJnBT+A=
|
||||
-----END CERTIFICATE-----
|
27
sources/docker/nginx/localhost.key
Normal file
27
sources/docker/nginx/localhost.key
Normal file
|
@ -0,0 +1,27 @@
|
|||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpAIBAAKCAQEAuHD3r5tvPQjm080BQmj9MbdCLxHOQfJ4Z6D51sxyRLZjeBxp
|
||||
rgTyeye4qKxuYdm7pmBzs/yyv11XqpOzPTtom7Lml23f7L2iIc93TkRnhplJdt90
|
||||
YsDCv3gPpHcAjrO/qUD5wIAcgi4Di2A6aO3KSt7rfZ0MNUvIPLFVN6SfbyrpqD7q
|
||||
8OeP2DIAGy8RHtawmmLUB/ofEfb+0zUS0IpqblI1XL36VCzf+leTyvyQq8pXKt7C
|
||||
FPPLgXwhFWLS9e1xbvC2QPA7VOL4I3ULURNBnaN9OTtn3EZoVtLlwgRscfcCYGAm
|
||||
NPf3qlQFASpBUcGwfG+aEWEowGJ6O8VtNgXPxwIDAQABAoIBACbhMWUkN9u+36Gw
|
||||
Kl7McOsk/V+cukTujvERXvknmcLgS7GLE7/qLQ9G/UcZKh+YXVUiKeG8GBX84DkF
|
||||
75etyUxg9vje4YAvLVlBOZ4XD1exQmo7inYyuhrQfUOnDkgGnhVYrA0nNFtAxeCA
|
||||
hW+PCMClozCUhXlKo0gf/Z3AJxewsVm4x+G73aU9t/yxm6A4Z2OEYGfD240uhfC/
|
||||
fEVNpL3xs2TPP4W90yw+Q+oZ0g/hmXKgFQ1PujD5+hGtiRLQ3v1Apb1LhPTz3pPg
|
||||
OK/VSWbDXBSESqU5aFfk3NP7KSnVfxkUVQk9MAnofq2p3BrPv0ovjgliyMHOV88/
|
||||
6xdkIBkCgYEA5QFSH63n9WuQz2ZHR7YrU/i8ATrQ9ex1RawLAVZA+YN+GC2/Kd+c
|
||||
GDyB1ed2v7o/DzCbiVE9WGhCLUE2WDp8J+MVIbgVDYnCx6wXLaMtkzSMtQMT6UV4
|
||||
+ks6FqvrjmzwdvtrX31XfHCvsGkPhHKeoUU0SnIwvbyxq2sNBdH0E2UCgYEAzi7Y
|
||||
KIQ/0ryekr6Mf8pAOaprxJX4ykArvTTGwzVazaumTNW0AArEnKNdebB+kVVko4h0
|
||||
2kUPbJTNwGTxJiuu7HJGE1vla++wlpyPryqghVPIgwVIQOjkV3guq8BbOPyB/xtv
|
||||
9yVJZqeJc0Jj+ZV7Cm+kQ514F3e1cpidYUUjQbsCgYA+Jj+dbVr4Vfr07nMF2UCl
|
||||
B2oug0HWnBevkuNht4DmtnLwKOoqeQ8p3LH31Vt66RbYDn8Ho06cwZ7EHWCcTTMI
|
||||
uC4x+n1sMSj1e5TGw/RIcQiGz5EFy97rPqNDJ+FDw/j2sYEQZznpAcQMgla9wUWf
|
||||
yuJIGfl0ZNNrDCB6peIxqQKBgQCKTo4dj6koefJ9SWkCB+/RPuqPsnJzaVxtzUtP
|
||||
gyjoMi6Z9/iI1rBQyp1XlfcxEnEx6cVI7W6NTbw/RPcmvcLXRUiQj+Jz5xMz1M3l
|
||||
mNiY1zz39sEjGZaivjHAcIZA0dF6CTOwO8jjHZtsP6rEr2sb8wvjd2wpgdmrh4h6
|
||||
yV//JQKBgQDL4q0becCvRcC8HYPt5LkxWHLvvOlP4Z8x19DzMw0xhvhqvtk7cuxy
|
||||
ioQckj/9Qa5icYqXGUY1eg2wSMe4mJdCbosXFDdPi3pW7eXJwmQmVCwHx0INDq6z
|
||||
Xn5hG0ZRioytwV8aqbq8k1PLHm6mmY71dH+riou2JwFD2py7RqBJqQ==
|
||||
-----END RSA PRIVATE KEY-----
|
91
sources/docker/nginx/nginx.conf
Normal file
91
sources/docker/nginx/nginx.conf
Normal file
|
@ -0,0 +1,91 @@
|
|||
user nginx;
|
||||
worker_processes 1;
|
||||
|
||||
pid /var/run/nginx.pid;
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
|
||||
http {
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||
'$status $body_bytes_sent "$http_referer" '
|
||||
'"$http_user_agent" "$http_x_forwarded_for"';
|
||||
|
||||
sendfile on;
|
||||
|
||||
keepalive_timeout 65;
|
||||
|
||||
# max_execution_time is 900
|
||||
proxy_read_timeout 910;
|
||||
|
||||
# Disable SSLv3 to protect us from POODLE & company
|
||||
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
|
||||
|
||||
server {
|
||||
listen *:443;
|
||||
|
||||
server_name localhost;
|
||||
|
||||
ssl on;
|
||||
ssl_certificate /etc/ssl/nginx/localhost.crt;
|
||||
ssl_certificate_key /etc/ssl/nginx/localhost.key;
|
||||
|
||||
root /var/www/z-push;
|
||||
index index.php;
|
||||
|
||||
error_log /var/log/nginx/zpush-error.log;
|
||||
access_log /var/log/nginx/zpush-access.log;
|
||||
|
||||
# Attachments 20MB max
|
||||
client_max_body_size 20m;
|
||||
client_body_buffer_size 128k;
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ index.php;
|
||||
}
|
||||
|
||||
location /Microsoft-Server-ActiveSync {
|
||||
rewrite ^(.*)$ /index.php last;
|
||||
}
|
||||
|
||||
location ~ .php$ {
|
||||
include /etc/nginx/fastcgi_params;
|
||||
fastcgi_index index.php;
|
||||
fastcgi_param HTTPS on;
|
||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||
fastcgi_pass zpushphpfpm:9000;
|
||||
# PHP max_execution_time is set to 900
|
||||
fastcgi_read_timeout 910;
|
||||
}
|
||||
|
||||
|
||||
# You don't really need all of the next, but I have them in my server
|
||||
location = /robots.txt {
|
||||
access_log off;
|
||||
log_not_found off;
|
||||
}
|
||||
|
||||
location = /favicon.ico {
|
||||
return 204;
|
||||
access_log off;
|
||||
log_not_found off;
|
||||
}
|
||||
|
||||
location ~ ^\. {
|
||||
access_log on;
|
||||
log_not_found off;
|
||||
deny all;
|
||||
}
|
||||
|
||||
location ~ ~$ {
|
||||
access_log off;
|
||||
log_not_found off;
|
||||
deny all;
|
||||
}
|
||||
}
|
||||
}
|
21
sources/docker/php-fpm/Dockerfile
Normal file
21
sources/docker/php-fpm/Dockerfile
Normal file
|
@ -0,0 +1,21 @@
|
|||
FROM fbiete/centos_epel_php_fpm:5.6
|
||||
MAINTAINER Francisco Miguel Biete <fbiete@gmail.com>
|
||||
|
||||
RUN yum clean all \
|
||||
&& yum install -y --enablerepo=remi-php56 \
|
||||
php-pecl-memprof \
|
||||
mailcap \
|
||||
&& yum clean all \
|
||||
&& cd /usr/local/src \
|
||||
&& curl -LSs https://gitlab.com/davical-project/awl/repository/archive.tar.gz | tar xz \
|
||||
&& echo "include_path=.:/usr/share/pear:/usr/share/php:/usr/local/src/awl.git/inc" >> /etc/php.ini \
|
||||
&& sed -i 's/max_execution_time = 30/max_execution_time = 900/g' /etc/php.ini \
|
||||
&& sed -i 's/max_input_time = 60/max_input_time = 300/g' /etc/php.ini \
|
||||
&& sed -i 's/post_max_size = 8M/post_max_size = 20M/g' /etc/php.ini \
|
||||
&& sed -i 's/upload_max_filesize = 2M/upload_max_filesize = 20M/g' /etc/php.ini \
|
||||
&& mkdir /var/log/z-push /var/lib/z-push \
|
||||
&& chown -R apache:apache /var/log/z-push /var/lib/z-push
|
||||
|
||||
VOLUME /var/www/z-push
|
||||
|
||||
|
|
@ -145,6 +145,4 @@ class Auth_SASL
|
|||
ZLog::Write(LOGLEVEL_ERROR, "Auth_SASL error: ". $message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
}
|
|
@ -43,8 +43,6 @@
|
|||
* @package Auth_SASL
|
||||
*/
|
||||
|
||||
require_once('include/Auth/SASL/Common.php');
|
||||
|
||||
class Auth_SASL_Anonymous extends Auth_SASL_Common
|
||||
{
|
||||
/**
|
||||
|
@ -67,5 +65,4 @@ class Auth_SASL_Anonymous extends Auth_SASL_Common
|
|||
{
|
||||
return $token;
|
||||
}
|
||||
}
|
||||
?>
|
||||
}
|
|
@ -125,5 +125,4 @@ class Auth_SASL_Common
|
|||
ZLog::Write(LOGLEVEL_ERROR, "SCRAM error: ". $message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
?>
|
||||
}
|
|
@ -43,8 +43,6 @@
|
|||
* @package Auth_SASL
|
||||
*/
|
||||
|
||||
require_once('include/Auth/SASL/Common.php');
|
||||
|
||||
class Auth_SASL_CramMD5 extends Auth_SASL_Common
|
||||
{
|
||||
/**
|
||||
|
@ -64,5 +62,4 @@ class Auth_SASL_CramMD5 extends Auth_SASL_Common
|
|||
{
|
||||
return $user . ' ' . $this->_HMAC_MD5($pass, $challenge);
|
||||
}
|
||||
}
|
||||
?>
|
||||
}
|
|
@ -43,8 +43,6 @@
|
|||
* @package Auth_SASL
|
||||
*/
|
||||
|
||||
require_once('include/Auth/SASL/Common.php');
|
||||
|
||||
class Auth_SASL_DigestMD5 extends Auth_SASL_Common
|
||||
{
|
||||
/**
|
||||
|
@ -193,5 +191,4 @@ class Auth_SASL_DigestMD5 extends Auth_SASL_Common
|
|||
return base64_encode($str);
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
}
|
|
@ -43,8 +43,6 @@
|
|||
* @package Auth_SASL
|
||||
*/
|
||||
|
||||
require_once('include/Auth/SASL/Common.php');
|
||||
|
||||
class Auth_SASL_External extends Auth_SASL_Common
|
||||
{
|
||||
/**
|
||||
|
@ -59,5 +57,4 @@ class Auth_SASL_External extends Auth_SASL_Common
|
|||
{
|
||||
return $authzid;
|
||||
}
|
||||
}
|
||||
?>
|
||||
}
|
|
@ -46,8 +46,6 @@
|
|||
* @package Auth_SASL
|
||||
*/
|
||||
|
||||
require_once('include/Auth/SASL/Common.php');
|
||||
|
||||
class Auth_SASL_Login extends Auth_SASL_Common
|
||||
{
|
||||
/**
|
||||
|
@ -61,5 +59,4 @@ class Auth_SASL_Login extends Auth_SASL_Common
|
|||
{
|
||||
return sprintf('LOGIN %s %s', $user, $pass);
|
||||
}
|
||||
}
|
||||
?>
|
||||
}
|
|
@ -43,8 +43,6 @@
|
|||
* @package Auth_SASL
|
||||
*/
|
||||
|
||||
require_once('include/Auth/SASL/Common.php');
|
||||
|
||||
class Auth_SASL_Plain extends Auth_SASL_Common
|
||||
{
|
||||
/**
|
||||
|
@ -59,5 +57,4 @@ class Auth_SASL_Plain extends Auth_SASL_Common
|
|||
{
|
||||
return $authzid . chr(0) . $authcid . chr(0) . $pass;
|
||||
}
|
||||
}
|
||||
?>
|
||||
}
|
|
@ -46,8 +46,6 @@
|
|||
* @package Auth_SASL
|
||||
*/
|
||||
|
||||
require_once('include/Auth/SASL/Common.php');
|
||||
|
||||
class Auth_SASL_SCRAM extends Auth_SASL_Common
|
||||
{
|
||||
/**
|
||||
|
@ -300,6 +298,4 @@ class Auth_SASL_SCRAM extends Auth_SASL_Common
|
|||
return base64_encode($str);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
}
|
|
@ -86,7 +86,6 @@ class Mail
|
|||
static function &factory($driver, $params = array())
|
||||
{
|
||||
$driver = strtolower($driver);
|
||||
@include_once 'include/Mail/' . $driver . '.php';
|
||||
$class = 'Mail_' . $driver;
|
||||
if (class_exists($class)) {
|
||||
$mailer = new $class($params);
|
||||
|
@ -197,7 +196,6 @@ class Mail
|
|||
|
||||
foreach ($headers as $key => $value) {
|
||||
if (strcasecmp($key, 'From') === 0) {
|
||||
include_once 'include/z_RFC822.php';
|
||||
$parser = new Mail_RFC822();
|
||||
$addresses = $parser->parseAddressList($value, 'localhost', false);
|
||||
//if (is_a($addresses, 'PEAR_Error')) {
|
||||
|
@ -255,8 +253,6 @@ class Mail
|
|||
*/
|
||||
function parseRecipients($recipients)
|
||||
{
|
||||
include_once 'include/z_RFC822.php';
|
||||
|
||||
// if we're passed an array, assume addresses are valid and
|
||||
// implode them before parsing.
|
||||
if (is_array($recipients)) {
|
||||
|
@ -282,6 +278,9 @@ class Mail
|
|||
}
|
||||
}
|
||||
|
||||
// Remove duplicated
|
||||
$recipients = array_unique($recipients);
|
||||
|
||||
return $recipients;
|
||||
}
|
||||
|
||||
|
|
|
@ -174,6 +174,24 @@ class Mail_smtp extends Mail {
|
|||
*/
|
||||
var $pipelining;
|
||||
|
||||
/**
|
||||
* Require verification of SSL certificate used.
|
||||
* @var bool
|
||||
*/
|
||||
var $verify_peer = true;
|
||||
|
||||
/**
|
||||
* Require verification of peer name
|
||||
* @var bool
|
||||
*/
|
||||
var $verify_peer_name = true;
|
||||
|
||||
/**
|
||||
* Allow self-signed certificates. Requires verify_peer
|
||||
* @var bool
|
||||
*/
|
||||
var $allow_self_signed = false;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
|
@ -211,6 +229,9 @@ class Mail_smtp extends Mail {
|
|||
if (isset($params['debug'])) $this->debug = (bool)$params['debug'];
|
||||
if (isset($params['persist'])) $this->persist = (bool)$params['persist'];
|
||||
if (isset($params['pipelining'])) $this->pipelining = (bool)$params['pipelining'];
|
||||
if (isset($params['verify_peer'])) $this->verify_peer = (bool)$params['verify_peer'];
|
||||
if (isset($params['verify_peer_name'])) $this->verify_peer_name = (bool)$params['verify_peer_name'];
|
||||
if (isset($params['allow_self_signed'])) $this->allow_self_signed = (bool)$params['allow_self_signed'];
|
||||
|
||||
// Deprecated options
|
||||
if (isset($params['verp'])) {
|
||||
|
@ -309,22 +330,6 @@ class Mail_smtp extends Mail {
|
|||
return $recipients;
|
||||
}
|
||||
|
||||
// FIX: Cc and Bcc headers are sent, but we need to make sure that the recipient list contains them
|
||||
foreach (array("CC", "cc", "Cc", "BCC", "Bcc", "bcc") as $key) {
|
||||
if (!empty($headers[$key])) {
|
||||
$extra_recipients = $this->parseRecipients($headers[$key]);
|
||||
if ($extra_recipients === false) {
|
||||
$this->_smtp->rset();
|
||||
return $extra_recipients;
|
||||
}
|
||||
$recipients = array_merge($recipients, $extra_recipients);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove repeated rcptTo
|
||||
$recipients = array_unique($recipients);
|
||||
|
||||
|
||||
foreach ($recipients as $recipient) {
|
||||
$res = $this->_smtp->rcptTo($recipient);
|
||||
//if (is_a($res, 'PEAR_Error')) {
|
||||
|
@ -378,11 +383,15 @@ class Mail_smtp extends Mail {
|
|||
return $this->_smtp;
|
||||
}
|
||||
|
||||
include_once 'include/Net/SMTP.php';
|
||||
$this->_smtp = &new Net_SMTP($this->host,
|
||||
$this->port,
|
||||
$this->localhost,
|
||||
$this->pipelining);
|
||||
$this->pipelining,
|
||||
0, //timeout
|
||||
null, //socket_options
|
||||
$this->verify_peer,
|
||||
$this->verify_peer_name,
|
||||
$this->allow_self_signed);
|
||||
|
||||
/* If we still don't have an SMTP object at this point, fail. */
|
||||
if (is_object($this->_smtp) === false) {
|
||||
|
@ -471,7 +480,8 @@ class Mail_smtp extends Mail {
|
|||
|
||||
/* Build our standardized error string. */
|
||||
return $text
|
||||
. ' [SMTP: ' . $error->getMessage()
|
||||
// . ' [SMTP: ' . $error->getMessage()
|
||||
. ' [SMTP: '
|
||||
. " (code: $code, response: $response)]";
|
||||
}
|
||||
|
||||
|
|
|
@ -33,7 +33,6 @@
|
|||
|
||||
//require_once 'PEAR.php';
|
||||
//require_once 'PEAR/Exception.php';
|
||||
require_once 'include/Net/Socket.php';
|
||||
|
||||
/**
|
||||
* Provides an implementation of the SMTP protocol using PEAR's
|
||||
|
@ -160,6 +159,27 @@ class Net_SMTP
|
|||
*/
|
||||
protected $_esmtp = array();
|
||||
|
||||
/**
|
||||
* Require verification of SSL certificate used.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $_verify_peer;
|
||||
|
||||
/**
|
||||
* Require verification of peer name
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $_verify_peer_name;
|
||||
|
||||
/**
|
||||
* Allow self-signed certificates. Requires verify_peer
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $_allow_self_signed;
|
||||
|
||||
/**
|
||||
* Instantiates a new Net_SMTP object, overriding any defaults
|
||||
* with parameters that are passed in.
|
||||
|
@ -177,10 +197,14 @@ class Net_SMTP
|
|||
* @param boolean $pipeling Use SMTP command pipelining
|
||||
* @param integer $timeout Socket I/O timeout in seconds.
|
||||
* @param array $socket_options Socket stream_context_create() options.
|
||||
* @param boolean $verify_peer Require verification of SSL certificate used
|
||||
* @param boolean $verify_peer_name Require verification of peer name
|
||||
* @param boolean $allow_self_signed Allow self-signed certificates. Requires verify_peer
|
||||
*/
|
||||
public function __construct($host = null, $port = null, $localhost = null,
|
||||
$pipelining = false, $timeout = 0,
|
||||
$socket_options = null)
|
||||
$socket_options = null,
|
||||
$verify_peer = true, $verify_peer_name = true, $allow_self_signed = false)
|
||||
{
|
||||
if (isset($host)) {
|
||||
$this->host = $host;
|
||||
|
@ -195,14 +219,33 @@ class Net_SMTP
|
|||
|
||||
$this->_socket = new Net_Socket();
|
||||
$this->_socket_options = $socket_options;
|
||||
|
||||
// SSL connection, we need to modify the socket_options
|
||||
if (strpos($this->host, "ssl://") === 0) {
|
||||
if ($this->_socket_options == null)
|
||||
$this->_socket_options = array();
|
||||
|
||||
if (!array_key_exists('ssl', $this->_socket_options))
|
||||
$this->_socket_options['ssl'] = array();
|
||||
|
||||
$this->_socket_options['ssl']['verify_peer'] = $verify_peer;
|
||||
$this->_socket_options['ssl']['allow_self_signed'] = $allow_self_signed;
|
||||
// This option was introduced in 5.6
|
||||
if (version_compare(phpversion(), "5.6.0", ">="))
|
||||
$this->_socket_options['ssl']['verify_peer_name'] = $verify_peer_name;
|
||||
}
|
||||
|
||||
$this->_timeout = $timeout;
|
||||
|
||||
// We also need this for use in the STARTTLS command
|
||||
$this->_verify_peer = $verify_peer;
|
||||
$this->_verify_peer_name = $verify_peer_name;
|
||||
$this->_allow_self_signed = $allow_self_signed;
|
||||
|
||||
/* Include the Auth_SASL package. If the package is available, we
|
||||
* enable the authentication methods that depend upon it. */
|
||||
if (@include_once 'include/Auth/SASL.php') {
|
||||
$this->setAuthMethod('CRAM-MD5', array($this, '_authCram_MD5'));
|
||||
$this->setAuthMethod('DIGEST-MD5', array($this, '_authDigest_MD5'));
|
||||
}
|
||||
$this->setAuthMethod('CRAM-MD5', array($this, '_authCram_MD5'));
|
||||
$this->setAuthMethod('DIGEST-MD5', array($this, '_authDigest_MD5'));
|
||||
|
||||
/* These standard authentication methods are always available. */
|
||||
$this->setAuthMethod('LOGIN', array($this, '_authLogin'), false);
|
||||
|
@ -262,8 +305,9 @@ class Net_SMTP
|
|||
|
||||
$result = $this->_socket->write($data);
|
||||
if ($result === false) {
|
||||
return Net_SMTP::raiseError('Failed to write to socket: ' . $result->getMessage(),
|
||||
$result);
|
||||
// return Net_SMTP::raiseError('Failed to write to socket: ' . $result->getMessage(),
|
||||
// $result);
|
||||
return Net_SMTP::raiseError('Failed to write to socket: ');
|
||||
}
|
||||
|
||||
return $result;
|
||||
|
@ -330,7 +374,8 @@ class Net_SMTP
|
|||
if (empty($line)) {
|
||||
$this->disconnect();
|
||||
return Net_SMTP::raiseError('Connection was closed',
|
||||
null, PEAR_ERROR_RETURN);
|
||||
// null, PEAR_ERROR_RETURN);
|
||||
null, 1);
|
||||
}
|
||||
|
||||
/* Read the code and store the rest in the arguments array. */
|
||||
|
@ -361,7 +406,8 @@ class Net_SMTP
|
|||
}
|
||||
|
||||
return Net_SMTP::raiseError('Invalid response code received from server',
|
||||
$this->_code, PEAR_ERROR_RETURN);
|
||||
// $this->_code, PEAR_ERROR_RETURN);
|
||||
$this->_code, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -429,8 +475,9 @@ class Net_SMTP
|
|||
$this->_socket_options);
|
||||
//if (PEAR::isError($result)) {
|
||||
if ($result === false) {
|
||||
return Net_SMTP::raiseError('Failed to connect socket: ' .
|
||||
$result->getMessage());
|
||||
// return Net_SMTP::raiseError('Failed to connect socket: ' .
|
||||
// $result->getMessage());
|
||||
return Net_SMTP::raiseError('Failed to connect socket: ');
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -509,7 +556,8 @@ class Net_SMTP
|
|||
//if (PEAR::isError($this->_parseResponse(250))) {
|
||||
if (($this->_parseResponse(250)) === false) {
|
||||
return Net_SMTP::raiseError('HELO was not accepted: ', $this->_code,
|
||||
PEAR_ERROR_RETURN);
|
||||
// PEAR_ERROR_RETURN);
|
||||
1);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -548,7 +596,8 @@ class Net_SMTP
|
|||
}
|
||||
|
||||
return Net_SMTP::raiseError('No supported authentication methods',
|
||||
null, PEAR_ERROR_RETURN);
|
||||
// null, PEAR_ERROR_RETURN);
|
||||
null, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -587,7 +636,7 @@ class Net_SMTP
|
|||
return $result;
|
||||
}
|
||||
//if (PEAR::isError($result = $this->_socket->enableCrypto(true, STREAM_CRYPTO_METHOD_TLS_CLIENT))) {
|
||||
if (($result = $this->_socket->enableCrypto(true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) === false) {
|
||||
if (($result = $this->_socket->enableCrypto(true, STREAM_CRYPTO_METHOD_TLS_CLIENT, $this->_verify_peer, $this->_verify_peer_name, $this->_allow_self_signed)) === false) {
|
||||
return $result;
|
||||
} elseif ($result !== true) {
|
||||
return Net_SMTP::raiseError('STARTTLS failed');
|
||||
|
|
|
@ -680,6 +680,9 @@ class Net_Socket
|
|||
* and false to disable encryption.
|
||||
* @param integer $type Type of encryption. See stream_socket_enable_crypto()
|
||||
* for values.
|
||||
* @param boolean $verify_peer Require verification of SSL certificate used
|
||||
* @param boolean $verify_peer_name Require verification of peer name
|
||||
* @param boolean $allow_self_signed Allow self-signed certificates. Requires verify_peer
|
||||
*
|
||||
* @see http://se.php.net/manual/en/function.stream-socket-enable-crypto.php
|
||||
* @access public
|
||||
|
@ -688,12 +691,19 @@ class Net_Socket
|
|||
* A PEAR_Error object is returned if the socket is not
|
||||
* connected
|
||||
*/
|
||||
function enableCrypto($enabled, $type)
|
||||
function enableCrypto($enabled, $type, $verify_peer, $verify_peer_name, $allow_self_signed)
|
||||
{
|
||||
if (version_compare(phpversion(), "5.1.0", ">=")) {
|
||||
if (!is_resource($this->fp)) {
|
||||
return $this->raiseError('not connected');
|
||||
}
|
||||
|
||||
// 5.6.0 Added verify_peer_name. verify_peer default changed to TRUE.
|
||||
if (version_compare(phpversion(), "5.6.0", ">="))
|
||||
stream_context_set_option($this->fp, array('ssl' => array('verify_peer' => $verify_peer, 'verify_peer_name' => $verify_peer_name, 'allow_self_signed' => $allow_self_signed)));
|
||||
else
|
||||
stream_context_set_option($this->fp, array('ssl' => array('verify_peer' => $verify_peer, 'allow_self_signed' => $allow_self_signed)));
|
||||
|
||||
return @stream_socket_enable_crypto($this->fp, $enabled, $type);
|
||||
} else {
|
||||
$msg = 'Net_Socket::enableCrypto() requires php version >= 5.1.0';
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -119,7 +119,16 @@ class iCalProp {
|
|||
* @param string $propstring The string from the iCalendar which contains this property.
|
||||
*/
|
||||
function ParseFrom( $propstring ) {
|
||||
$this->rendered = (strlen($propstring) < 72 ? $propstring : null); // Only pre-rendered if we didn't unescape it
|
||||
// $this->rendered = (strlen($propstring) < 72 ? $propstring : null); // Only pre-rendered if we didn't unescape it
|
||||
// FMBIETE - unset rendered content; if we alter some properties inside an object (VEVENT/ATTENDEE for example) we won't see the changes calling Render
|
||||
// FIXME: if you find the bug, let me know
|
||||
//$ical = new iCalComponent();
|
||||
//$ical->ParseFrom(VCALENDAR DATA);
|
||||
// Doing this will refresh the rendered data, but if this line is not executed, you won't see PARTSTAT changed
|
||||
//$ical->SetPValue("METHOD", "REPLY");
|
||||
//$ical->SetCPParameterValue("VEVENT", "ATTENDEE", "PARTSTAT", "ACCEPTED");
|
||||
//printf("%s\n", $ical->Render());
|
||||
unset($this->rendered);
|
||||
|
||||
$unescaped = preg_replace( '{\\\\[nN]}', "\n", $propstring);
|
||||
|
||||
|
@ -227,7 +236,13 @@ class iCalProp {
|
|||
*/
|
||||
function SetParameterValue( $name, $value ) {
|
||||
if ( isset($this->rendered) ) unset($this->rendered);
|
||||
$this->parameters[$name] = $value;
|
||||
// Unset parameter
|
||||
if ($value === null) {
|
||||
unset($this->parameters[$name]);
|
||||
}
|
||||
else {
|
||||
$this->parameters[$name] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -553,7 +568,13 @@ class iCalComponent {
|
|||
for ( $i = 0; $i < count($this->properties); $i++ ) {
|
||||
if ( $this->properties[$i]->Name() == $type ) {
|
||||
if ( isset($this->rendered) ) unset($this->rendered);
|
||||
$this->properties[$i]->Value($value);
|
||||
// FMBIETE - unset property
|
||||
if ($value == null) {
|
||||
unset($this->properties[$i]);
|
||||
}
|
||||
else {
|
||||
$this->properties[$i]->Value($value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -566,14 +587,22 @@ class iCalComponent {
|
|||
* @param string $property_name Type/Name of the property
|
||||
* @param string $parameter_name Type/Name of the parameter
|
||||
* @param string $value New value of the parameter
|
||||
* @param string $condition_value Change the parameter_value only if the property_value is equals to condition_value
|
||||
*/
|
||||
function SetCPParameterValue( $component_type, $property_name, $parameter_name, $value ) {
|
||||
function SetCPParameterValue( $component_type, $property_name, $parameter_name, $value, $condition_value = null ) {
|
||||
for ( $j = 0; $j < count($this->components); $j++ ) {
|
||||
if ( $this->components[$j]->GetType() == $component_type ) {
|
||||
for ( $i = 0; $i < count($this->components[$j]->properties); $i++ ) {
|
||||
if ( $this->components[$j]->properties[$i]->Name() == $property_name ) {
|
||||
if ( isset($this->components[$j]->rendered) ) unset($this->components[$j]->rendered);
|
||||
$this->components[$j]->properties[$i]->SetParameterValue($parameter_name, $value);
|
||||
if ($condition_value === null) {
|
||||
$this->components[$j]->properties[$i]->SetParameterValue($parameter_name, $value);
|
||||
}
|
||||
else {
|
||||
if (strcasecmp($this->components[$j]->properties[$i]->Value(), $condition_value) == 0) {
|
||||
$this->components[$j]->properties[$i]->SetParameterValue($parameter_name, $value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,7 +52,7 @@
|
|||
* @author Sean Coates <sean@php.net>
|
||||
* @copyright 2003-2006 PEAR <pear-group@php.net>
|
||||
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
|
||||
* @version CVS: $Id: mimeDecode.php 305875 2010-12-01 07:17:10Z alan_k $
|
||||
* @version CVS: $Id: mimeDecode.php 335147 2014-10-27 08:41:39Z alan_k $
|
||||
* @link http://pear.php.net/package/Mail_mime
|
||||
*/
|
||||
|
||||
|
@ -68,7 +68,6 @@
|
|||
*
|
||||
* used "old" method of checking if called statically, as this is deprecated between php 5.0.0 and 5.3.0
|
||||
* (isStatic of decode() around line 215)
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
|
@ -160,6 +159,7 @@ class Mail_mimeDecode
|
|||
*/
|
||||
var $_decode_headers;
|
||||
|
||||
|
||||
/**
|
||||
* Flag to determine whether to include attached messages
|
||||
* as body in the returned object. Depends on $_include_bodies
|
||||
|
@ -178,7 +178,7 @@ class Mail_mimeDecode
|
|||
* @param string The input to decode
|
||||
* @access public
|
||||
*/
|
||||
function Mail_mimeDecode($input, $deprecated_linefeed = '')
|
||||
function Mail_mimeDecode($input)
|
||||
{
|
||||
list($header, $body) = $this->_splitBodyHeader($input);
|
||||
|
||||
|
@ -202,6 +202,7 @@ class Mail_mimeDecode
|
|||
* decode_bodies - Whether to decode the bodies
|
||||
* of the parts. (Transfer encoding)
|
||||
* decode_headers - Whether to decode headers
|
||||
*
|
||||
* input - If called statically, this will be treated
|
||||
* as the input
|
||||
* charset - convert all data to this charset
|
||||
|
@ -211,7 +212,7 @@ class Mail_mimeDecode
|
|||
function decode($params = null)
|
||||
{
|
||||
// determine if this method has been called statically
|
||||
$isStatic = !(isset($this) && get_class($this) == __CLASS__);
|
||||
$isStatic = empty($this) || !is_a($this, __CLASS__);
|
||||
|
||||
// Have we been called statically?
|
||||
// If so, create an object and pass details to that.
|
||||
|
@ -237,6 +238,11 @@ class Mail_mimeDecode
|
|||
$this->_charset = isset($params['charset']) ?
|
||||
strtolower($params['charset']) : 'utf-8';
|
||||
|
||||
|
||||
if (is_string($this->_decode_headers) && !function_exists('iconv')) {
|
||||
$this->raiseError('header decode conversion requested, however iconv is missing');
|
||||
}
|
||||
|
||||
$structure = $this->_decode($this->_header, $this->_body);
|
||||
if ($structure === false) {
|
||||
$structure = $this->raiseError($this->_error);
|
||||
|
@ -263,7 +269,7 @@ class Mail_mimeDecode
|
|||
$headers = $this->_parseHeaders($headers);
|
||||
|
||||
foreach ($headers as $value) {
|
||||
$value['value'] = $this->_decode_headers ? $this->_decodeHeader($value['value']) : $value['value'];
|
||||
$value['value'] = $this->_decodeHeader($value['value']);
|
||||
if (isset($return->headers[strtolower($value['name'])]) AND !is_array($return->headers[strtolower($value['name'])])) {
|
||||
$return->headers[strtolower($value['name'])] = array($return->headers[strtolower($value['name'])]);
|
||||
$return->headers[strtolower($value['name'])][] = $value['value'];
|
||||
|
@ -284,7 +290,12 @@ class Mail_mimeDecode
|
|||
case 'content-type':
|
||||
$content_type = $this->_parseHeaderValue($headers[$key]['value']);
|
||||
|
||||
if (preg_match('/([0-9a-z+.-]+)\/([0-9a-z+.-]+)/i', $content_type['value'], $regs)) {
|
||||
if (preg_match('/([0-9a-z+.-]+)\/([0-9a-z+.-]+)\; name=\"([0-9a-z+.-]+)/i', $headers[$key]['value'], $regs)) {
|
||||
$return->ctype_primary = $regs[1];
|
||||
$return->ctype_secondary = $regs[2];
|
||||
$return->filename = $regs[3];
|
||||
}
|
||||
elseif (preg_match('/([0-9a-z+.-]+)\/([0-9a-z+.-]+)/i', $content_type['value'], $regs)) {
|
||||
$return->ctype_primary = $regs[1];
|
||||
$return->ctype_secondary = $regs[2];
|
||||
}
|
||||
|
@ -317,22 +328,24 @@ class Mail_mimeDecode
|
|||
case 'text/plain':
|
||||
$encoding = isset($content_transfer_encoding) ? $content_transfer_encoding['value'] : '7bit';
|
||||
$charset = isset($return->ctype_parameters['charset']) ? $return->ctype_parameters['charset'] : $this->_charset;
|
||||
$this->_include_bodies ? $return->body = ($this->_decode_bodies ? $this->_decodeBody($body, $encoding, $charset) : $body) : null;
|
||||
$this->_include_bodies ? $return->body = ($this->_decode_bodies ? $this->_decodeBody($body, $encoding, $charset, true) : $body) : null;
|
||||
break;
|
||||
|
||||
case 'text/html':
|
||||
$encoding = isset($content_transfer_encoding) ? $content_transfer_encoding['value'] : '7bit';
|
||||
$charset = isset($return->ctype_parameters['charset']) ? $return->ctype_parameters['charset'] : $this->_charset;
|
||||
$this->_include_bodies ? $return->body = ($this->_decode_bodies ? $this->_decodeBody($body, $encoding, $charset) : $body) : null;
|
||||
$this->_include_bodies ? $return->body = ($this->_decode_bodies ? $this->_decodeBody($body, $encoding, $charset, true) : $body) : null;
|
||||
break;
|
||||
|
||||
case 'multipart/signed': // PGP
|
||||
case 'multipart/encrypted': // #190 encrypted parts will be treated as normal ones
|
||||
case 'multipart/parallel':
|
||||
case 'multipart/appledouble': // Appledouble mail
|
||||
case 'multipart/report': // RFC1892
|
||||
case 'multipart/signed': // PGP
|
||||
case 'multipart/digest':
|
||||
case 'multipart/alternative':
|
||||
case 'multipart/related':
|
||||
case 'multipart/relative': //#20431 - android
|
||||
case 'multipart/mixed':
|
||||
case 'application/vnd.wap.multipart.related':
|
||||
if(!isset($content_type['other']['boundary'])){
|
||||
|
@ -353,6 +366,7 @@ class Mail_mimeDecode
|
|||
break;
|
||||
|
||||
case 'message/rfc822':
|
||||
case 'message/delivery-status': // #bug #18693
|
||||
if ($this->_rfc822_bodies) {
|
||||
$encoding = isset($content_transfer_encoding) ? $content_transfer_encoding['value'] : '7bit';
|
||||
$charset = isset($return->ctype_parameters['charset']) ? $return->ctype_parameters['charset'] : $this->_charset;
|
||||
|
@ -364,8 +378,29 @@ class Mail_mimeDecode
|
|||
'decode_bodies' => $this->_decode_bodies,
|
||||
'decode_headers' => $this->_decode_headers));
|
||||
unset($obj);
|
||||
|
||||
// #213, KD 2015-06-29 - Always inline them because there is no "type" to them (they're text)
|
||||
$return->disposition = 'inline';
|
||||
break;
|
||||
|
||||
// #190, KD 2015-06-09 - Add type for S/MIME Encrypted messages; these must have the filename set explicitly (it won't work otherwise)
|
||||
//and then falls through for the rest on purpose.
|
||||
case 'application/x-pkcs7-mime':
|
||||
case 'application/pkcs7-mime':
|
||||
if (!isset($content_transfer_encoding['value'])) {
|
||||
$content_transfer_encoding['value'] = 'base64';
|
||||
}
|
||||
// if there is no explicit charset, then don't try to convert to default charset, and make sure that only text mimetypes are converted
|
||||
$charset = (isset($return->ctype_parameters['charset']) && ((isset($return->ctype_primary) && $return->ctype_primary == 'text') || !isset($return->ctype_primary)) ) ? $return->ctype_parameters['charset'] : '';
|
||||
$part->body = ($this->_decode_bodies ? $this->_decodeBody($body, $content_transfer_encoding['value'], $charset, false) : $body);
|
||||
$ctype = explode('/', strtolower($content_type['value']));
|
||||
$part->ctype_parameters['name'] = 'smime.p7m';
|
||||
$part->ctype_primary = $ctype[0];
|
||||
$part->ctype_secondary = $ctype[1];
|
||||
$part->d_parameters['size'] = strlen($part->body);
|
||||
$return->parts[] = $part;
|
||||
// Fall through intentionally
|
||||
|
||||
default:
|
||||
if(!isset($content_transfer_encoding['value']))
|
||||
$content_transfer_encoding['value'] = '7bit';
|
||||
|
@ -460,7 +495,6 @@ class Mail_mimeDecode
|
|||
*/
|
||||
function _parseHeaders($input)
|
||||
{
|
||||
|
||||
if ($input !== '') {
|
||||
// Unfold the input
|
||||
$input = preg_replace("/\r?\n/", "\r\n", $input);
|
||||
|
@ -471,12 +505,25 @@ class Mail_mimeDecode
|
|||
$input = preg_replace("/\r\n(\t| )+/", ' ', $input);
|
||||
|
||||
$headers = explode("\r\n", trim($input));
|
||||
|
||||
$got_start = false;
|
||||
foreach ($headers as $value) {
|
||||
if (!$got_start) {
|
||||
// munge headers for mbox style from
|
||||
if ($value[0] == '>') {
|
||||
$value = substring($value, 1); // remove mbox >
|
||||
}
|
||||
if (substr($value,0,5) == 'From ') {
|
||||
$value = 'Return-Path: ' . substr($value, 5);
|
||||
} else {
|
||||
$got_start = true;
|
||||
}
|
||||
}
|
||||
|
||||
$hdr_name = substr($value, 0, $pos = strpos($value, ':'));
|
||||
$hdr_value = substr($value, $pos+1);
|
||||
if($hdr_value[0] == ' ')
|
||||
if($hdr_value[0] == ' ') {
|
||||
$hdr_value = substr($hdr_value, 1);
|
||||
}
|
||||
|
||||
$return[] = array(
|
||||
'name' => $hdr_name,
|
||||
|
@ -497,15 +544,25 @@ class Mail_mimeDecode
|
|||
* robust as it could be. Eg. header comments
|
||||
* in the wrong place will probably break it.
|
||||
*
|
||||
* Extra things this can handle
|
||||
* filename*0=......
|
||||
* filename*1=......
|
||||
*
|
||||
* This is where lines are broken in, and need merging.
|
||||
*
|
||||
* filename*0*=ENC'lang'urlencoded data.
|
||||
* filename*1*=ENC'lang'urlencoded data.
|
||||
*
|
||||
*
|
||||
*
|
||||
* @param string Header value to parse
|
||||
* @return array Contains parsed result
|
||||
* @access private
|
||||
*/
|
||||
function _parseHeaderValue($input)
|
||||
{
|
||||
|
||||
if (($pos = strpos($input, ';')) === false) {
|
||||
$input = $this->_decode_headers ? $this->_decodeHeader($input) : $input;
|
||||
if (($pos = strpos($input, ';')) === false) {
|
||||
$input = $this->_decodeHeader($input);
|
||||
$return['value'] = trim($input);
|
||||
return $return;
|
||||
}
|
||||
|
@ -513,7 +570,7 @@ class Mail_mimeDecode
|
|||
|
||||
|
||||
$value = substr($input, 0, $pos);
|
||||
$value = $this->_decode_headers ? $this->_decodeHeader($value) : $value;
|
||||
$value = $this->_decodeHeader($value);
|
||||
$return['value'] = trim($value);
|
||||
$input = trim(substr($input, $pos+1));
|
||||
|
||||
|
@ -557,7 +614,6 @@ class Mail_mimeDecode
|
|||
if ($key) { // a key without a value..
|
||||
$key= trim($key);
|
||||
$return['other'][$key] = '';
|
||||
$return['other'][strtolower($key)] = '';
|
||||
}
|
||||
$key = '';
|
||||
}
|
||||
|
@ -574,7 +630,11 @@ class Mail_mimeDecode
|
|||
$i++;
|
||||
continue; // skip leading spaces after '=' or after '"'
|
||||
}
|
||||
if (!$escaped && ($c == '"' || $c == "'")) {
|
||||
|
||||
// do not de-quote 'xxx*= itesm..
|
||||
$key_is_trans = $key[strlen($key)-1] == '*';
|
||||
|
||||
if (!$key_is_trans && !$escaped && ($c == '"' || $c == "'")) {
|
||||
// start quoted area..
|
||||
$q = $c;
|
||||
// in theory should not happen raw text in value part..
|
||||
|
@ -586,25 +646,7 @@ class Mail_mimeDecode
|
|||
// got end....
|
||||
if (!$escaped && $c == ';') {
|
||||
|
||||
$val = trim($val);
|
||||
$added = false;
|
||||
if (preg_match('/\*[0-9]+$/', $key)) {
|
||||
// this is the extended aaa*0=...;aaa*1=.... code
|
||||
// it assumes the pieces arrive in order, and are valid...
|
||||
$key = preg_replace('/\*[0-9]+$/', '', $key);
|
||||
if (isset($return['other'][$key])) {
|
||||
$return['other'][$key] .= $val;
|
||||
if (strtolower($key) != $key) {
|
||||
$return['other'][strtolower($key)] .= $val;
|
||||
}
|
||||
$added = true;
|
||||
}
|
||||
// continue and use standard setters..
|
||||
}
|
||||
if (!$added) {
|
||||
$return['other'][$key] = $val;
|
||||
$return['other'][strtolower($key)] = $val;
|
||||
}
|
||||
$return['other'][$key] = trim($val);
|
||||
$val = false;
|
||||
$key = '';
|
||||
$lq = false;
|
||||
|
@ -636,29 +678,58 @@ class Mail_mimeDecode
|
|||
if (strlen(trim($key)) || $val !== false) {
|
||||
|
||||
$val = trim($val);
|
||||
$added = false;
|
||||
if ($val !== false && preg_match('/\*[0-9]+$/', $key)) {
|
||||
// no dupes due to our crazy regexp.
|
||||
$key = preg_replace('/\*[0-9]+$/', '', $key);
|
||||
if (isset($return['other'][$key])) {
|
||||
$return['other'][$key] .= $val;
|
||||
if (strtolower($key) != $key) {
|
||||
$return['other'][strtolower($key)] .= $val;
|
||||
}
|
||||
$added = true;
|
||||
}
|
||||
// continue and use standard setters..
|
||||
}
|
||||
if (!$added) {
|
||||
$return['other'][$key] = $val;
|
||||
$return['other'][strtolower($key)] = $val;
|
||||
}
|
||||
|
||||
$return['other'][$key] = $val;
|
||||
}
|
||||
|
||||
|
||||
$clean_others = array();
|
||||
// merge added values. eg. *1[*]
|
||||
foreach($return['other'] as $key =>$val) {
|
||||
if (preg_match('/\*[0-9]+\**$/', $key)) {
|
||||
$key = preg_replace('/(.*)\*[0-9]+(\**)$/', '\1\2', $key);
|
||||
if (isset($clean_others[$key])) {
|
||||
$clean_others[$key] .= $val;
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
$clean_others[$key] = $val;
|
||||
|
||||
}
|
||||
|
||||
// handle language translation of '*' ending others.
|
||||
foreach( $clean_others as $key =>$val) {
|
||||
if ( $key[strlen($key)-1] != '*') {
|
||||
$clean_others[strtolower($key)] = $val;
|
||||
continue;
|
||||
}
|
||||
unset($clean_others[$key]);
|
||||
$key = substr($key,0,-1);
|
||||
//extended-initial-value := [charset] "'" [language] "'"
|
||||
// extended-other-values
|
||||
$match = array();
|
||||
$info = preg_match("/^([^']+)'([^']*)'(.*)$/", $val, $match);
|
||||
|
||||
$clean_others[$key] = urldecode($match[3]);
|
||||
$clean_others[strtolower($key)] = $clean_others[$key];
|
||||
$clean_others[strtolower($key).'-charset'] = $match[1];
|
||||
$clean_others[strtolower($key).'-language'] = $match[2];
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
$return['other'] = $clean_others;
|
||||
|
||||
// decode values.
|
||||
foreach($return['other'] as $key =>$val) {
|
||||
$return['other'][$key] = $this->_decode_headers ? $this->_decodeHeader($val) : $val;
|
||||
$charset = isset($return['other'][$key . '-charset']) ?
|
||||
$return['other'][$key . '-charset'] : false;
|
||||
|
||||
$return['other'][$key] = $this->_decodeHeader($val, $charset);
|
||||
}
|
||||
//print_r($return);
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
|
@ -670,7 +741,7 @@ class Mail_mimeDecode
|
|||
* @return array Contains array of resulting mime parts
|
||||
* @access private
|
||||
*/
|
||||
function _boundarySplit($input, $boundary)
|
||||
function _boundarySplit($input, $boundary, $eatline = false)
|
||||
{
|
||||
$parts = array();
|
||||
|
||||
|
@ -680,7 +751,10 @@ class Mail_mimeDecode
|
|||
if ($boundary == $bs_check) {
|
||||
$boundary = $bs_possible;
|
||||
}
|
||||
$tmp = preg_split("/--".preg_quote($boundary, '/')."((?=\s)|--)/", $input);
|
||||
// eatline is used by multipart/signed.
|
||||
$tmp = $eatline ?
|
||||
preg_split("/\r?\n--".preg_quote($boundary, '/')."(|--)\n/", $input) :
|
||||
preg_split("/--".preg_quote($boundary, '/')."((?=\s)|--)/", $input);
|
||||
|
||||
$len = count($tmp) -1;
|
||||
for ($i = 1; $i < $len; $i++) {
|
||||
|
@ -708,19 +782,23 @@ class Mail_mimeDecode
|
|||
*/
|
||||
function _decodeHeader($input)
|
||||
{
|
||||
if (!$this->_decode_headers) {
|
||||
return $input;
|
||||
}
|
||||
// Remove white space between encoded-words
|
||||
$input = preg_replace('/(=\?[^?]+\?(q|b)\?[^?]*\?=)(\s)+=\?/i', '\1=?', $input);
|
||||
|
||||
$encodedwords = false;
|
||||
$charset = '';
|
||||
|
||||
// For each encoded-word...
|
||||
while (preg_match('/(=\?([^?]+)\?(q|b)\?([^?]*)\?=)/i', $input, $matches)) {
|
||||
$encodedwords = true;
|
||||
|
||||
$encoded = $matches[1];
|
||||
$charset = $matches[2];
|
||||
$encoded = $matches[1];
|
||||
$charset = $matches[2];
|
||||
$encoding = $matches[3];
|
||||
$text = $matches[4];
|
||||
$text = $matches[4];
|
||||
|
||||
switch (strtolower($encoding)) {
|
||||
case 'b':
|
||||
|
@ -730,13 +808,13 @@ class Mail_mimeDecode
|
|||
case 'q':
|
||||
$text = str_replace('_', ' ', $text);
|
||||
preg_match_all('/=([a-f0-9]{2})/i', $text, $matches);
|
||||
foreach($matches[1] as $value) {
|
||||
$text = str_replace('='.$value, chr(hexdec($value)), $text);
|
||||
}
|
||||
foreach ($matches[1] as $value)
|
||||
$text = str_replace('=' . $value, chr(hexdec($value)), $text);
|
||||
break;
|
||||
}
|
||||
|
||||
$input = str_replace($encoded, $this->_autoconvert_encoding($text, $charset), $input);
|
||||
$text = $this->_autoconvert_encoding($text, $charset);
|
||||
$input = str_replace($encoded, $text, $input);
|
||||
}
|
||||
|
||||
if (!$encodedwords) {
|
||||
|
@ -761,21 +839,20 @@ class Mail_mimeDecode
|
|||
{
|
||||
switch (strtolower($encoding)) {
|
||||
case 'quoted-printable':
|
||||
$input_decoded = $this->_quotedPrintableDecode($input);
|
||||
return $detectCharset ? $this->_autoconvert_encoding($input_decoded, $charset) : $input_decoded;
|
||||
$input = $this->_quotedPrintableDecode($input);
|
||||
break;
|
||||
|
||||
case 'base64':
|
||||
$input_decoded = base64_decode($input);
|
||||
return $detectCharset ? $this->_autoconvert_encoding($input_decoded, $charset) : $input_decoded;
|
||||
$input = base64_decode($input);
|
||||
break;
|
||||
|
||||
case '7bit':
|
||||
case '8bit':
|
||||
default:
|
||||
return $detectCharset ? $this->_autoconvert_encoding($input, $charset) : $input;
|
||||
break;
|
||||
}
|
||||
|
||||
return $detectCharset ? $this->_autoconvert_encoding($input, $charset) : $input;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -805,17 +882,26 @@ class Mail_mimeDecode
|
|||
if (function_exists("mb_detect_order")) {
|
||||
$mb_order = array_merge(array($supposed_encoding), mb_detect_order());
|
||||
set_error_handler('Mail_mimeDecode::_iconv_notice_handler');
|
||||
|
||||
// Default value in case of error
|
||||
$detected_encoding = $supposed_encoding;
|
||||
|
||||
try {
|
||||
$input_converted = iconv(mb_detect_encoding($input, $mb_order, true), $this->_charset, $input);
|
||||
$detected_encoding = mb_detect_encoding($input, $mb_order, true);
|
||||
// In some cases mb_detect_encoding returns an empty string
|
||||
if ($detected_encoding === false || strlen($detected_encoding) == 0) {
|
||||
$detected_encoding = $supposed_encoding;
|
||||
}
|
||||
$input_converted = iconv($detected_encoding, $this->_charset, $input);
|
||||
}
|
||||
catch(Exception $ex) {
|
||||
$this->raiseError($ex->getMessage());
|
||||
}
|
||||
restore_error_handler();
|
||||
|
||||
if (strlen($input_converted) == 0 && strlen($input) != 0) {
|
||||
ZLog::Write(LOGLEVEL_INFO, "Mail_mimeDecode() - Text cannot be correctly decoded, using original text. Expect encoding errors");
|
||||
$input_converted = mb_convert_encoding($input, 'UTF-8', 'UTF-8');
|
||||
if ($input_converted === false || mb_strlen($input_converted, $this->_charset) !== mb_strlen($input, $detected_encoding)) {
|
||||
ZLog::Write(LOGLEVEL_DEBUG, "Mail_mimeDecode()::_autoconvert_encoding(): Text cannot be correctly decoded, using original text. This will be ok if the part is not text, otherwise expect encoding errors");
|
||||
$input_converted = $input;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -836,7 +922,10 @@ class Mail_mimeDecode
|
|||
$input = preg_replace("/=\r?\n/", '', $input);
|
||||
|
||||
// Replace encoded characters
|
||||
$input = preg_replace('/=([a-f0-9]{2})/ie', "chr(hexdec('\\1'))", $input);
|
||||
|
||||
$cb = create_function('$matches', ' return chr(hexdec($matches[0]));');
|
||||
|
||||
$input = preg_replace_callback( '/=([a-f0-9]{2})/i', $cb, $input);
|
||||
|
||||
return $input;
|
||||
}
|
||||
|
@ -923,14 +1012,21 @@ class Mail_mimeDecode
|
|||
* @param string $message mimedecode message(part)
|
||||
* @param string $message message subtype
|
||||
* @param string &$body body reference
|
||||
* @param boolean $replace_nr replace \n\r with \n
|
||||
*
|
||||
* @return void
|
||||
* @access public
|
||||
*/
|
||||
static function getBodyRecursive($message, $subtype, &$body) {
|
||||
static function getBodyRecursive($message, $subtype, &$body, $replace_nr = false) {
|
||||
if(!isset($message->ctype_primary)) return;
|
||||
if(strcasecmp($message->ctype_primary,"text")==0 && strcasecmp($message->ctype_secondary,$subtype)==0 && isset($message->body))
|
||||
$body .= $message->body;
|
||||
if(strcasecmp($message->ctype_primary, "text") == 0 && strcasecmp($message->ctype_secondary, $subtype) == 0 && isset($message->body)) {
|
||||
if ($replace_nr) {
|
||||
$body .= str_replace("\n", "\r\n", str_replace("\r", "", $message->body));
|
||||
}
|
||||
else {
|
||||
$body .= $message->body;
|
||||
}
|
||||
}
|
||||
|
||||
if(strcasecmp($message->ctype_primary,"multipart")==0 && isset($message->parts) && is_array($message->parts)) {
|
||||
foreach($message->parts as $part) {
|
||||
|
@ -938,7 +1034,7 @@ class Mail_mimeDecode
|
|||
// Content-Type: text/plain; charset=us-ascii; name="hareandtoroise.txt" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="hareandtoroise.txt"
|
||||
// We don't want to show that file text (outlook doesn't show it), so if we have content-disposition we don't apply recursivity
|
||||
if(!isset($part->disposition)) {
|
||||
Mail_mimeDecode::getBodyRecursive($part, $subtype, $body);
|
||||
Mail_mimeDecode::getBodyRecursive($part, $subtype, $body, $replace_nr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1117,4 +1213,5 @@ class Mail_mimeDecode
|
|||
ZLog::Write(LOGLEVEL_ERROR, "mimeDecode error: ". $message);
|
||||
return false;
|
||||
}
|
||||
} // End of class
|
||||
|
||||
} // End of class
|
||||
|
|
|
@ -1,144 +0,0 @@
|
|||
<?php
|
||||
/***********************************************
|
||||
* File : stringstreamwrapper.php
|
||||
* Project : Z-Push
|
||||
* Descr : Wraps a string as a standard php stream
|
||||
* The used method names are predefined and can not be altered.
|
||||
*
|
||||
* Created : 24.11.2011
|
||||
*
|
||||
* Copyright 2007 - 2013 Zarafa Deutschland GmbH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation with the following additional
|
||||
* term according to sec. 7:
|
||||
*
|
||||
* According to sec. 7 of the GNU Affero General Public License, version 3,
|
||||
* the terms of the AGPL are supplemented with the following terms:
|
||||
*
|
||||
* "Zarafa" is a registered trademark of Zarafa B.V.
|
||||
* "Z-Push" is a registered trademark of Zarafa Deutschland GmbH
|
||||
* The licensing of the Program under the AGPL does not imply a trademark license.
|
||||
* Therefore any rights, title and interest in our trademarks remain entirely with us.
|
||||
*
|
||||
* However, if you propagate an unmodified version of the Program you are
|
||||
* allowed to use the term "Z-Push" to indicate that you distribute the Program.
|
||||
* Furthermore you may use our trademarks where it is necessary to indicate
|
||||
* the intended purpose of a product or service provided you use it in accordance
|
||||
* with honest practices in industrial or commercial matters.
|
||||
* If you want to propagate modified versions of the Program under the name "Z-Push",
|
||||
* you may only do so if you have a written permission by Zarafa Deutschland GmbH
|
||||
* (to acquire a permission please contact Zarafa at trademark@zarafa.com).
|
||||
*
|
||||
* 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/>.
|
||||
*
|
||||
* Consult LICENSE file for details
|
||||
************************************************/
|
||||
|
||||
class StringStreamWrapper {
|
||||
const PROTOCOL = "stringstream";
|
||||
|
||||
private $stringstream;
|
||||
private $position;
|
||||
private $stringlength;
|
||||
|
||||
/**
|
||||
* Opens the stream
|
||||
* The string to be streamed is passed over the context
|
||||
*
|
||||
* @param string $path Specifies the URL that was passed to the original function
|
||||
* @param string $mode The mode used to open the file, as detailed for fopen()
|
||||
* @param int $options Holds additional flags set by the streams API
|
||||
* @param string $opened_path If the path is opened successfully, and STREAM_USE_PATH is set in options,
|
||||
* opened_path should be set to the full path of the file/resource that was actually opened.
|
||||
*
|
||||
* @access public
|
||||
* @return boolean
|
||||
*/
|
||||
public function stream_open($path, $mode, $options, &$opened_path) {
|
||||
$contextOptions = stream_context_get_options($this->context);
|
||||
if (!isset($contextOptions[self::PROTOCOL]['string']))
|
||||
return false;
|
||||
|
||||
$this->position = 0;
|
||||
|
||||
// this is our stream!
|
||||
$this->stringstream = $contextOptions[self::PROTOCOL]['string'];
|
||||
|
||||
$this->stringlength = strlen($this->stringstream);
|
||||
ZLog::Write(LOGLEVEL_DEBUG, sprintf("StringStreamWrapper::stream_open(): initialized stream length: %d", $this->stringlength));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads from stream
|
||||
*
|
||||
* @param int $len amount of bytes to be read
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function stream_read($len) {
|
||||
$data = substr($this->stringstream, $this->position, $len);
|
||||
$this->position += strlen($data);
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current position on stream
|
||||
*
|
||||
* @access public
|
||||
* @return int
|
||||
*/
|
||||
public function stream_tell() {
|
||||
return $this->position;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if 'end of file' is reached
|
||||
*
|
||||
* @access public
|
||||
* @return boolean
|
||||
*/
|
||||
public function stream_eof() {
|
||||
return ($this->position >= $this->stringlength);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves information about a stream
|
||||
*
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function stream_stat() {
|
||||
return array(
|
||||
7 => $this->stringlength,
|
||||
'size' => $this->stringlength,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a StringStreamWrapper
|
||||
*
|
||||
* @param string $string The string to be wrapped
|
||||
*
|
||||
* @access public
|
||||
* @return StringStreamWrapper
|
||||
*/
|
||||
static public function Open($string) {
|
||||
$context = stream_context_create(array(self::PROTOCOL => array('string' => &$string)));
|
||||
return fopen(self::PROTOCOL . "://",'r', false, $context);
|
||||
}
|
||||
}
|
||||
|
||||
stream_wrapper_register(StringStreamWrapper::PROTOCOL, "StringStreamWrapper")
|
||||
|
||||
?>
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* RFC 822 Email address list validation Utility
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENSE:
|
||||
*
|
||||
|
@ -63,10 +63,11 @@
|
|||
*
|
||||
* @author Richard Heyes <richard@phpguru.org>
|
||||
* @author Chuck Hagenbuch <chuck@horde.org>
|
||||
* @version $Revision: 294749 $
|
||||
* @version $Revision$
|
||||
* @license BSD
|
||||
* @package Mail
|
||||
*/
|
||||
|
||||
class Mail_RFC822 {
|
||||
|
||||
/**
|
||||
|
@ -120,7 +121,6 @@ class Mail_RFC822 {
|
|||
/**
|
||||
* The number of groups that have been found in the address list.
|
||||
* @var integer $num_groups
|
||||
* @access public
|
||||
*/
|
||||
var $num_groups = 0;
|
||||
|
||||
|
@ -141,7 +141,6 @@ class Mail_RFC822 {
|
|||
* Sets up the object. The address must either be set here or when
|
||||
* calling parseAddressList(). One or the other.
|
||||
*
|
||||
* @access public
|
||||
* @param string $address The address(es) to validate.
|
||||
* @param string $default_domain Default domain/host etc. If not supplied, will be set to localhost.
|
||||
* @param boolean $nest_groups Whether to return the structure with groups nested for easier viewing.
|
||||
|
@ -149,7 +148,7 @@ class Mail_RFC822 {
|
|||
*
|
||||
* @return object Mail_RFC822 A new Mail_RFC822 object.
|
||||
*/
|
||||
function Mail_RFC822($address = null, $default_domain = null, $nest_groups = null, $validate = null, $limit = null)
|
||||
public function __construct($address = null, $default_domain = null, $nest_groups = null, $validate = null, $limit = null)
|
||||
{
|
||||
if (isset($address)) $this->address = $address;
|
||||
if (isset($default_domain)) $this->default_domain = $default_domain;
|
||||
|
@ -162,7 +161,6 @@ class Mail_RFC822 {
|
|||
* Starts the whole process. The address must either be set here
|
||||
* or when creating the object. One or the other.
|
||||
*
|
||||
* @access public
|
||||
* @param string $address The address(es) to validate.
|
||||
* @param string $default_domain Default domain/host etc.
|
||||
* @param boolean $nest_groups Whether to return the structure with groups nested for easier viewing.
|
||||
|
@ -170,7 +168,7 @@ class Mail_RFC822 {
|
|||
*
|
||||
* @return array A structured array of addresses.
|
||||
*/
|
||||
function parseAddressList($address = null, $default_domain = null, $nest_groups = null, $validate = null, $limit = null)
|
||||
public function parseAddressList($address = null, $default_domain = null, $nest_groups = null, $validate = null, $limit = null)
|
||||
{
|
||||
if (!isset($this) || !isset($this->mailRFC822)) {
|
||||
$obj = new Mail_RFC822($address, $default_domain, $nest_groups, $validate, $limit);
|
||||
|
@ -178,6 +176,7 @@ class Mail_RFC822 {
|
|||
}
|
||||
|
||||
if (isset($address)) $this->address = $address;
|
||||
// z-push addition
|
||||
if (strlen(trim($this->address)) == 0) return array();
|
||||
if (isset($default_domain)) $this->default_domain = $default_domain;
|
||||
if (isset($nest_groups)) $this->nestGroups = $nest_groups;
|
||||
|
@ -223,11 +222,10 @@ class Mail_RFC822 {
|
|||
/**
|
||||
* Splits an address into separate addresses.
|
||||
*
|
||||
* @access private
|
||||
* @param string $address The addresses to split.
|
||||
* @return boolean Success or failure.
|
||||
*/
|
||||
function _splitAddresses($address)
|
||||
protected function _splitAddresses($address)
|
||||
{
|
||||
if (!empty($this->limit) && count($this->addresses) == $this->limit) {
|
||||
return '';
|
||||
|
@ -299,11 +297,10 @@ class Mail_RFC822 {
|
|||
/**
|
||||
* Checks for a group at the start of the string.
|
||||
*
|
||||
* @access private
|
||||
* @param string $address The address to check.
|
||||
* @return boolean Whether or not there is a group at the start of the string.
|
||||
*/
|
||||
function _isGroup($address)
|
||||
protected function _isGroup($address)
|
||||
{
|
||||
// First comma not in quotes, angles or escaped:
|
||||
$parts = explode(',', $address);
|
||||
|
@ -323,12 +320,11 @@ class Mail_RFC822 {
|
|||
/**
|
||||
* A common function that will check an exploded string.
|
||||
*
|
||||
* @access private
|
||||
* @param array $parts The exloded string.
|
||||
* @param string $char The char that was exploded on.
|
||||
* @return mixed False if the string contains unclosed quotes/brackets, or the string on success.
|
||||
*/
|
||||
function _splitCheck($parts, $char)
|
||||
protected function _splitCheck($parts, $char)
|
||||
{
|
||||
$string = $parts[0];
|
||||
|
||||
|
@ -356,12 +352,11 @@ class Mail_RFC822 {
|
|||
/**
|
||||
* Checks if a string has unclosed quotes or not.
|
||||
*
|
||||
* @access private
|
||||
* @param string $string The string to check.
|
||||
* @return boolean True if there are unclosed quotes inside the string,
|
||||
* false otherwise.
|
||||
*/
|
||||
function _hasUnclosedQuotes($string)
|
||||
protected function _hasUnclosedQuotes($string)
|
||||
{
|
||||
$string = trim($string);
|
||||
$iMax = strlen($string);
|
||||
|
@ -393,12 +388,11 @@ class Mail_RFC822 {
|
|||
* Checks if a string has an unclosed brackets or not. IMPORTANT:
|
||||
* This function handles both angle brackets and square brackets;
|
||||
*
|
||||
* @access private
|
||||
* @param string $string The string to check.
|
||||
* @param string $chars The characters to check for.
|
||||
* @return boolean True if there are unclosed brackets inside the string, false otherwise.
|
||||
*/
|
||||
function _hasUnclosedBrackets($string, $chars)
|
||||
protected function _hasUnclosedBrackets($string, $chars)
|
||||
{
|
||||
$num_angle_start = substr_count($string, $chars[0]);
|
||||
$num_angle_end = substr_count($string, $chars[1]);
|
||||
|
@ -417,13 +411,12 @@ class Mail_RFC822 {
|
|||
/**
|
||||
* Sub function that is used only by hasUnclosedBrackets().
|
||||
*
|
||||
* @access private
|
||||
* @param string $string The string to check.
|
||||
* @param integer &$num The number of occurences.
|
||||
* @param string $char The character to count.
|
||||
* @return integer The number of occurences of $char in $string, adjusted for backslashes.
|
||||
*/
|
||||
function _hasUnclosedBracketsSub($string, &$num, $char)
|
||||
protected function _hasUnclosedBracketsSub($string, &$num, $char)
|
||||
{
|
||||
$parts = explode($char, $string);
|
||||
for ($i = 0; $i < count($parts); $i++){
|
||||
|
@ -439,11 +432,10 @@ class Mail_RFC822 {
|
|||
/**
|
||||
* Function to begin checking the address.
|
||||
*
|
||||
* @access private
|
||||
* @param string $address The address to validate.
|
||||
* @return mixed False on failure, or a structured array of address information on success.
|
||||
*/
|
||||
function _validateAddress($address)
|
||||
protected function _validateAddress($address)
|
||||
{
|
||||
$is_group = false;
|
||||
$addresses = array();
|
||||
|
@ -484,14 +476,6 @@ class Mail_RFC822 {
|
|||
$addresses[] = $address['address'];
|
||||
}
|
||||
|
||||
// Check that $addresses is set, if address like this:
|
||||
// Groupname:;
|
||||
// Then errors were appearing.
|
||||
if (!count($addresses)){
|
||||
$this->error = 'Empty group.';
|
||||
return false;
|
||||
}
|
||||
|
||||
// Trim the whitespace from all of the address strings.
|
||||
array_map('trim', $addresses);
|
||||
|
||||
|
@ -532,11 +516,10 @@ class Mail_RFC822 {
|
|||
/**
|
||||
* Function to validate a phrase.
|
||||
*
|
||||
* @access private
|
||||
* @param string $phrase The phrase to check.
|
||||
* @return boolean Success or failure.
|
||||
*/
|
||||
function _validatePhrase($phrase)
|
||||
protected function _validatePhrase($phrase)
|
||||
{
|
||||
// Splits on one or more Tab or space.
|
||||
$parts = preg_split('/[ \\x09]+/', $phrase, -1, PREG_SPLIT_NO_EMPTY);
|
||||
|
@ -573,11 +556,10 @@ class Mail_RFC822 {
|
|||
* can split a list of addresses up before encoding personal names
|
||||
* (umlauts, etc.), for example.
|
||||
*
|
||||
* @access private
|
||||
* @param string $atom The string to check.
|
||||
* @return boolean Success or failure.
|
||||
*/
|
||||
function _validateAtom($atom)
|
||||
protected function _validateAtom($atom)
|
||||
{
|
||||
if (!$this->validate) {
|
||||
// Validation has been turned off; assume the atom is okay.
|
||||
|
@ -606,11 +588,10 @@ class Mail_RFC822 {
|
|||
* Function to validate quoted string, which is:
|
||||
* quoted-string = <"> *(qtext/quoted-pair) <">
|
||||
*
|
||||
* @access private
|
||||
* @param string $qstring The string to check
|
||||
* @return boolean Success or failure.
|
||||
*/
|
||||
function _validateQuotedString($qstring)
|
||||
protected function _validateQuotedString($qstring)
|
||||
{
|
||||
// Leading and trailing "
|
||||
$qstring = substr($qstring, 1, -1);
|
||||
|
@ -624,11 +605,10 @@ class Mail_RFC822 {
|
|||
* mailbox = addr-spec ; simple address
|
||||
* / phrase route-addr ; name and route-addr
|
||||
*
|
||||
* @access public
|
||||
* @param string &$mailbox The string to check.
|
||||
* @return boolean Success or failure.
|
||||
*/
|
||||
function validateMailbox(&$mailbox)
|
||||
public function validateMailbox(&$mailbox)
|
||||
{
|
||||
// A couple of defaults.
|
||||
$phrase = '';
|
||||
|
@ -718,11 +698,10 @@ class Mail_RFC822 {
|
|||
* Angle brackets have already been removed at the point of
|
||||
* getting to this function.
|
||||
*
|
||||
* @access private
|
||||
* @param string $route_addr The string to check.
|
||||
* @return mixed False on failure, or an array containing validated address/route information on success.
|
||||
*/
|
||||
function _validateRouteAddr($route_addr)
|
||||
protected function _validateRouteAddr($route_addr)
|
||||
{
|
||||
// Check for colon.
|
||||
if (strpos($route_addr, ':') !== false) {
|
||||
|
@ -768,11 +747,10 @@ class Mail_RFC822 {
|
|||
* Function to validate a route, which is:
|
||||
* route = 1#("@" domain) ":"
|
||||
*
|
||||
* @access private
|
||||
* @param string $route The string to check.
|
||||
* @return mixed False on failure, or the validated $route on success.
|
||||
*/
|
||||
function _validateRoute($route)
|
||||
protected function _validateRoute($route)
|
||||
{
|
||||
// Split on comma.
|
||||
$domains = explode(',', trim($route));
|
||||
|
@ -791,11 +769,10 @@ class Mail_RFC822 {
|
|||
*
|
||||
* domain = sub-domain *("." sub-domain)
|
||||
*
|
||||
* @access private
|
||||
* @param string $domain The string to check.
|
||||
* @return mixed False on failure, or the validated domain on success.
|
||||
*/
|
||||
function _validateDomain($domain)
|
||||
protected function _validateDomain($domain)
|
||||
{
|
||||
// Note the different use of $subdomains and $sub_domains
|
||||
$subdomains = explode('.', $domain);
|
||||
|
@ -819,11 +796,10 @@ class Mail_RFC822 {
|
|||
* Function to validate a subdomain:
|
||||
* subdomain = domain-ref / domain-literal
|
||||
*
|
||||
* @access private
|
||||
* @param string $subdomain The string to check.
|
||||
* @return boolean Success or failure.
|
||||
*/
|
||||
function _validateSubdomain($subdomain)
|
||||
protected function _validateSubdomain($subdomain)
|
||||
{
|
||||
if (preg_match('|^\[(.*)]$|', $subdomain, $arr)){
|
||||
if (!$this->_validateDliteral($arr[1])) return false;
|
||||
|
@ -839,11 +815,10 @@ class Mail_RFC822 {
|
|||
* Function to validate a domain literal:
|
||||
* domain-literal = "[" *(dtext / quoted-pair) "]"
|
||||
*
|
||||
* @access private
|
||||
* @param string $dliteral The string to check.
|
||||
* @return boolean Success or failure.
|
||||
*/
|
||||
function _validateDliteral($dliteral)
|
||||
protected function _validateDliteral($dliteral)
|
||||
{
|
||||
return !preg_match('/(.)[][\x0D\\\\]/', $dliteral, $matches) && $matches[1] != '\\';
|
||||
}
|
||||
|
@ -853,11 +828,10 @@ class Mail_RFC822 {
|
|||
*
|
||||
* addr-spec = local-part "@" domain
|
||||
*
|
||||
* @access private
|
||||
* @param string $addr_spec The string to check.
|
||||
* @return mixed False on failure, or the validated addr-spec on success.
|
||||
*/
|
||||
function _validateAddrSpec($addr_spec)
|
||||
protected function _validateAddrSpec($addr_spec)
|
||||
{
|
||||
$addr_spec = trim($addr_spec);
|
||||
|
||||
|
@ -884,17 +858,16 @@ class Mail_RFC822 {
|
|||
* Function to validate the local part of an address:
|
||||
* local-part = word *("." word)
|
||||
*
|
||||
* @access private
|
||||
* @param string $local_part
|
||||
* @return mixed False on failure, or the validated local part on success.
|
||||
*/
|
||||
function _validateLocalPart($local_part)
|
||||
protected function _validateLocalPart($local_part)
|
||||
{
|
||||
$parts = explode('.', $local_part);
|
||||
$words = array();
|
||||
|
||||
// Split the local_part into words.
|
||||
while (count($parts) > 0){
|
||||
while (count($parts) > 0) {
|
||||
$words[] = $this->_splitCheck($parts, '.');
|
||||
for ($i = 0; $i < $this->index + 1; $i++) {
|
||||
array_shift($parts);
|
||||
|
@ -903,6 +876,10 @@ class Mail_RFC822 {
|
|||
|
||||
// Validate each word.
|
||||
foreach ($words as $word) {
|
||||
// word cannot be empty (#17317)
|
||||
if ($word === '') {
|
||||
return false;
|
||||
}
|
||||
// If this word contains an unquoted space, it is invalid. (6.2.4)
|
||||
if (strpos($word, ' ') && $word[0] !== '"')
|
||||
{
|
||||
|
|
|
@ -31,14 +31,14 @@
|
|||
|
||||
It was modified by me (Andreas Brodowski) to allow compressed RTF being uncompressed by code I ported from
|
||||
Java to PHP and adapted according the needs of Z-Push.
|
||||
|
||||
|
||||
Currently it is being used to detect empty RTF Streams from Nokia Phones in MfE Clients
|
||||
|
||||
It needs to be used by other backend writers that needs to have notes in calendar, appointment or tasks
|
||||
|
||||
It needs to be used by other backend writers that needs to have notes in calendar, appointment or tasks
|
||||
objects to be written to their databases since devices send them usually in RTF Format... With Zarafa
|
||||
you can write them directly to DB and Zarafa is doing the conversion job. Other Groupware systems usually
|
||||
don't have this possibility...
|
||||
|
||||
|
||||
*/
|
||||
|
||||
class rtf {
|
||||
|
@ -77,7 +77,7 @@ class rtf {
|
|||
0xBDBDF21C,0xCABAC28A,0x53B39330,0x24B4A3A6,0xBAD03605,0xCDD70693,0x54DE5729,0x23D967BF,
|
||||
0xB3667A2E,0xC4614AB8,0x5D681B02,0x2A6F2B94,0xB40BBE37,0xC30C8EA1,0x5A05DF1B,0x2D02EF8D,
|
||||
);
|
||||
|
||||
|
||||
var $rtf; // rtf core stream
|
||||
var $rtf_len; // length in characters of the stream (get performace due avoiding calling strlen everytime)
|
||||
var $err = array(); // array of error message, no entities on no error
|
||||
|
@ -157,14 +157,14 @@ class rtf {
|
|||
"strikethru" => "strike",
|
||||
);
|
||||
|
||||
|
||||
|
||||
function rtf() {
|
||||
$this->rtf_len = 0;
|
||||
$this->rtf = '';
|
||||
|
||||
$this->out = '';
|
||||
}
|
||||
|
||||
|
||||
// loadrtf - load the raw rtf data to be converted by this class
|
||||
// data = the raw rtf
|
||||
function loadrtf($data) {
|
||||
|
@ -177,7 +177,7 @@ class rtf {
|
|||
};
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
function output($typ) {
|
||||
switch($typ) {
|
||||
case "ascii": $this->wantASCII = true; break;
|
||||
|
@ -194,16 +194,16 @@ class rtf {
|
|||
$in = 16;
|
||||
if ($header['cSize'] != strlen($src)-4) {
|
||||
debugLog("Stream too short");
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if ($header['crc32'] != $this->LZRTFCalcCRC32($src,16,(($header['cSize']+4))-16)) {
|
||||
debugLog("CRC MISMATCH");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if ($header['magic'] == 0x414c454d) { // uncompressed RTF - return as is.
|
||||
$dest = substr($src,$in,$header['uSize']);
|
||||
$dest = substr($src,$in,$header['uSize']);
|
||||
} else if ($header['magic'] == 0x75465a4c) { // compressed RTF - uncompress.
|
||||
$dst = $this->LZRTF_HDR_DATA;
|
||||
$out = $this->LZRTF_HDR_LEN;
|
||||
|
@ -233,7 +233,7 @@ class rtf {
|
|||
debugLog("Unknown Magic");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
return $dest;
|
||||
}
|
||||
|
||||
|
@ -241,14 +241,14 @@ class rtf {
|
|||
// buf = the whole rtf data part
|
||||
// off = start point of crc calculation
|
||||
// len = length of data to calculate CRC for
|
||||
// function is necessary since in RTF there is no XOR 0xffffffff being done (said to be 0x00 unsafe CRC32 calculation
|
||||
// function is necessary since in RTF there is no XOR 0xffffffff being done (said to be 0x00 unsafe CRC32 calculation
|
||||
function LZRTFCalcCRC32($buf, $off, $len) {
|
||||
$c=0;
|
||||
$end = $off + $len;
|
||||
for($i=$off;$i < $end;$i++) {
|
||||
$c=$this->CRC32_TABLE[($c ^ ord($buf{$i})) & 0xFF] ^ (($c >> 8) & 0x00ffffff);
|
||||
}
|
||||
return $c;
|
||||
return $c;
|
||||
}
|
||||
|
||||
function parserInit() { /* Default values according to the specs */
|
||||
|
@ -257,9 +257,9 @@ class rtf {
|
|||
"beginparagraph" => true,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
function parseControl($control, $parameter) {
|
||||
switch ($control) {
|
||||
switch ($control) {
|
||||
case "fonttbl": // font table definition start
|
||||
$this->flags["fonttbl"] = true; // signal fonttable control words they are allowed to behave as expected
|
||||
break;
|
||||
|
@ -276,14 +276,14 @@ class rtf {
|
|||
case "fs": // sets the current fontsize; is used by stylesheets (which are therefore generated on the fly
|
||||
$this->flags["fontsize"] = $parameter;
|
||||
break;
|
||||
|
||||
|
||||
case "qc": // handle center alignment
|
||||
$this->flags["alignment"] = "center";
|
||||
break;
|
||||
case "qr": // handle right alignment
|
||||
$this->flags["alignment"] = "right";
|
||||
break;
|
||||
|
||||
|
||||
case "pard": // reset paragraph settings (only alignment)
|
||||
$this->flags["alignment"] = "";
|
||||
break;
|
||||
|
@ -361,7 +361,7 @@ class rtf {
|
|||
/*
|
||||
Dispatch the control word to the output stream
|
||||
*/
|
||||
|
||||
|
||||
function flushControl() {
|
||||
if(preg_match("/^([A-Za-z]+)(-?[0-9]*) ?$/", $this->cword, $match)) {
|
||||
$this->parseControl($match[1], $match[2]);
|
||||
|
@ -377,7 +377,7 @@ class rtf {
|
|||
/*
|
||||
If output stream supports comments, dispatch it
|
||||
*/
|
||||
|
||||
|
||||
function flushComment($comment) {
|
||||
if($this->wantXML || $this->wantHTML) {
|
||||
$this->out.="<!-- ".$comment." -->";
|
||||
|
@ -391,7 +391,7 @@ class rtf {
|
|||
function flushGroup($state) {
|
||||
if($state == "open") { /* push onto the stack */
|
||||
array_push($this->stack, $this->flags);
|
||||
|
||||
|
||||
if($this->wantXML)
|
||||
$this->out.="<group>";
|
||||
}
|
||||
|
@ -432,7 +432,7 @@ class rtf {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
flush text in queue
|
||||
*/
|
||||
|
@ -445,7 +445,7 @@ class rtf {
|
|||
$this->flags["fonttbl_want_fcharset"] = "";
|
||||
$this->queue = "";
|
||||
}
|
||||
|
||||
|
||||
// output logic
|
||||
if (strlen($this->queue)) {
|
||||
/*
|
||||
|
@ -474,7 +474,7 @@ class rtf {
|
|||
}
|
||||
$this->out .= "\">";
|
||||
}
|
||||
|
||||
|
||||
/* define new style for that span */
|
||||
$this->styles["f".$this->flags["fonttbl_current_read"]."s".$this->flags["fontsize"]] = "font-family:".$this->fonttable[$this->flags["fonttbl_current_read"]]["charset"]." font-size:".$this->flags["fontsize"].";";
|
||||
/* write span start */
|
||||
|
@ -498,10 +498,10 @@ class rtf {
|
|||
/*
|
||||
handle special charactes like \'ef
|
||||
*/
|
||||
|
||||
|
||||
function flushSpecial($special) {
|
||||
if(strlen($special) == 2) {
|
||||
if($this->wantASCII)
|
||||
if($this->wantASCII)
|
||||
$this->out .= chr(hexdec('0x'.$special));
|
||||
else if($this->wantXML)
|
||||
$this->out .= "<special value=\"".$special."\"/>";
|
||||
|
@ -591,7 +591,7 @@ class rtf {
|
|||
case "{":
|
||||
if($this->cw) {
|
||||
$this->flushControl();
|
||||
$this->cw = false;
|
||||
$this->cw = false;
|
||||
$this->cfirst = false;
|
||||
} else
|
||||
$this->flushQueue();
|
||||
|
@ -601,15 +601,15 @@ class rtf {
|
|||
case "}":
|
||||
if($this->cw) {
|
||||
$this->flushControl();
|
||||
$this->cw = false;
|
||||
$this->cw = false;
|
||||
$this->cfirst = false;
|
||||
} else
|
||||
$this->flushQueue();
|
||||
|
||||
|
||||
$this->flushGroup("close");
|
||||
break;
|
||||
case "\\":
|
||||
if($this->cfirst) { // catches '\\'
|
||||
case "\\":
|
||||
if($this->cfirst) { // catches '\\'
|
||||
$this->queue .= "\\"; // replaced single quotes
|
||||
$this->cfirst = false;
|
||||
$this->cw = false;
|
||||
|
@ -644,10 +644,10 @@ class rtf {
|
|||
$this->flushSpecial($this->rtf[$i+1].$this->rtf[$i+2]);
|
||||
$i+=2;
|
||||
$specialmatch = true;
|
||||
$this->cw = false;
|
||||
$this->cfirst = false;
|
||||
$this->cw = false;
|
||||
$this->cfirst = false;
|
||||
$this->cword = "";
|
||||
} else
|
||||
} else
|
||||
if(preg_match("/^[{}\*]$/", $this->rtf[$i])) {
|
||||
$this->flushComment("control symbols not yet handled");
|
||||
$specialmatch = true;
|
||||
|
@ -686,10 +686,10 @@ class rtf {
|
|||
$this->queue .= $this->rtf[$i];
|
||||
break;
|
||||
}
|
||||
} else
|
||||
} else
|
||||
$this->queue .= $this->rtf[$i];
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
|
@ -701,7 +701,4 @@ class rtf {
|
|||
$this->makeStyles();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
}
|
|
@ -8,7 +8,7 @@
|
|||
* caldav-client-v2.php by xbgmsharp <xbgmsharp@gmail.com>.
|
||||
*
|
||||
* Copyright Andrew McMillan (original caldav-client-v2.php), Jean-Louis Dupond (cURL code), xbgmsharp (bugfixes)
|
||||
* Copyright Thorsten Köster
|
||||
* Copyright Thorsten Köster
|
||||
* License GNU LGPL version 3 or later (http://www.gnu.org/licenses/lgpl-3.0.txt)
|
||||
*/
|
||||
|
||||
|
@ -69,6 +69,11 @@ class CalDAVClient {
|
|||
*/
|
||||
protected $calendar_urls;
|
||||
|
||||
/**
|
||||
* Construct URL
|
||||
*/
|
||||
protected $url;
|
||||
|
||||
/**
|
||||
* The useragent which is send to the caldav server
|
||||
*
|
||||
|
@ -89,8 +94,7 @@ class CalDAVClient {
|
|||
*
|
||||
* @var resource
|
||||
*/
|
||||
private $curl;
|
||||
|
||||
private $curl = false;
|
||||
|
||||
private $synctoken = array();
|
||||
|
||||
|
@ -102,25 +106,61 @@ class CalDAVClient {
|
|||
* @param string $pass The password for that user
|
||||
*/
|
||||
function __construct( $caldav_url, $user, $pass ) {
|
||||
$this->url = $caldav_url;
|
||||
$this->user = $user;
|
||||
$this->pass = $pass;
|
||||
$this->auth = $user . ':' . $pass;
|
||||
$this->headers = array();
|
||||
|
||||
$parsed_url = parse_url($caldav_url);
|
||||
if ($parsed_url == FALSE) {
|
||||
ZLog::Write(LOGLEVEL_ERROR, sprintf('Couldn\'t parse URL: %s', $caldav_url));
|
||||
} else
|
||||
$this->server = $parsed_url['scheme'] . '://' . $parsed_url['host'] . ':' . $parsed_url['port'];
|
||||
$this->base_url = $parsed_url['path'];
|
||||
// $this->base_url .= !empty($parsed_url['query']) ? '?' . $parsed_url['query'] : '';
|
||||
// $this->base_url .= !empty($parsed_url['fragment']) ? '#' . $parsed_url['fragment'] : '';
|
||||
if ($parsed_url === false) {
|
||||
ZLog::Write(LOGLEVEL_ERROR, sprintf("BackendCalDAV->caldav_backend(): Couldn't parse URL: %s", $caldav_url));
|
||||
return;
|
||||
}
|
||||
|
||||
if (substr($this->base_url, -1, 1) !== '/') {
|
||||
$this->base_url = $this->base_url . '/';
|
||||
}
|
||||
$this->server = $parsed_url['scheme'] . '://' . $parsed_url['host'] . ':' . $parsed_url['port'];
|
||||
$this->base_url = $parsed_url['path'];
|
||||
//ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendCalDAV->caldav_backend(): base_url '%s'", $this->base_url));
|
||||
//$this->base_url .= !empty($parsed_url['query']) ? '?' . $parsed_url['query'] : '';
|
||||
//$this->base_url .= !empty($parsed_url['fragment']) ? '#' . $parsed_url['fragment'] : '';
|
||||
|
||||
if (substr($this->base_url, -1) !== '/') {
|
||||
$this->base_url = $this->base_url . '/';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the CalDAV server is reachable
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function CheckConnection() {
|
||||
$result = $this->DoRequest($this->url, 'OPTIONS');
|
||||
|
||||
switch ($this->httpResponseCode) {
|
||||
case 200:
|
||||
case 207:
|
||||
case 401:
|
||||
$status = true;
|
||||
break;
|
||||
default:
|
||||
$status = false;
|
||||
}
|
||||
|
||||
return $status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnect curl connection
|
||||
*
|
||||
*/
|
||||
public function Disconnect() {
|
||||
if ($this->curl !== false) {
|
||||
curl_close($this->curl);
|
||||
$this->curl = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds an If-Match or If-None-Match header
|
||||
|
@ -178,7 +218,7 @@ class CalDAVClient {
|
|||
|
||||
|
||||
public function curl_init() {
|
||||
if (empty($this->curl)) {
|
||||
if ($this->curl === false) {
|
||||
$this->curl = curl_init();
|
||||
curl_setopt($this->curl, CURLOPT_HEADER, true);
|
||||
curl_setopt($this->curl, CURLOPT_SSL_VERIFYHOST, false);
|
||||
|
@ -210,6 +250,7 @@ class CalDAVClient {
|
|||
|
||||
curl_setopt($this->curl, CURLOPT_URL, $url);
|
||||
curl_setopt($this->curl, CURLOPT_CUSTOMREQUEST, $method);
|
||||
curl_setopt($this->curl, CURLOPT_CONNECTTIMEOUT, 30); // 30 seconds it's already too big
|
||||
|
||||
if ($content !== null)
|
||||
{
|
||||
|
@ -231,9 +272,9 @@ class CalDAVClient {
|
|||
|
||||
$this->xmlResponse = '';
|
||||
|
||||
//ZLog::Write(LOGLEVEL_DEBUG, sprintf("Request:\n%s\n", $content));
|
||||
// ZLog::Write(LOGLEVEL_DEBUG, sprintf("Request:\n%s\n", $content));
|
||||
$response = curl_exec($this->curl);
|
||||
//ZLog::Write(LOGLEVEL_DEBUG, sprintf("Reponse:\n%s\n", $response));
|
||||
// ZLog::Write(LOGLEVEL_DEBUG, sprintf("Reponse:\n%s\n", $response));
|
||||
$header_size = curl_getinfo($this->curl, CURLINFO_HEADER_SIZE);
|
||||
$this->httpResponseCode = curl_getinfo($this->curl, CURLINFO_HTTP_CODE);
|
||||
$this->httpResponseHeaders = trim(substr($response, 0, $header_size));
|
||||
|
@ -253,7 +294,7 @@ class CalDAVClient {
|
|||
* @return array The allowed options
|
||||
*/
|
||||
function DoOptionsRequest( $url = null ) {
|
||||
$headers = $this->DoRequest($url, "OPTIONS");
|
||||
$headers = $this->DoRequest($url === null ? $this->url : $url, "OPTIONS");
|
||||
$options_header = preg_replace( '/^.*Allow: ([a-z, ]+)\r?\n.*/is', '$1', $headers );
|
||||
$options = array_flip( preg_split( '/[, ]+/', $options_header ));
|
||||
return $options;
|
||||
|
@ -315,7 +356,6 @@ class CalDAVClient {
|
|||
}
|
||||
if ( !isset($etag) || $etag == '' ) {
|
||||
ZLog::Write(LOGLEVEL_DEBUG, sprintf("No etag in:\n%s\n", $this->httpResponseHeaders));
|
||||
$save_request = $this->httpRequest;
|
||||
$save_response_headers = $this->httpResponseHeaders;
|
||||
$this->DoHEADRequest( $url );
|
||||
if ( preg_match( '{^Etag:\s+"([^"]*)"\s*$}im', $this->httpResponseHeaders, $matches ) ) {
|
||||
|
@ -324,7 +364,6 @@ class CalDAVClient {
|
|||
if ( !isset($etag) || $etag == '' ) {
|
||||
ZLog::Write(LOGLEVEL_DEBUG, sprintf("Still No etag in:\n%s\n", $this->httpResponseHeaders));
|
||||
}
|
||||
$this->httpRequest = $save_request;
|
||||
$this->httpResponseHeaders = $save_response_headers;
|
||||
}
|
||||
return $etag;
|
||||
|
@ -904,8 +943,9 @@ EOFILTER;
|
|||
$this->SetCalendar($relative_url);
|
||||
}
|
||||
|
||||
$hasToken = !$initial && isset($this->synctoken[$this->calendar_url]);
|
||||
if ($support_dav_sync) {
|
||||
$token = ($initial ? "" : $this->synctoken[$this->calendar_url]);
|
||||
$token = ($hasToken ? $this->synctoken[$this->calendar_url] : "");
|
||||
|
||||
$body = <<<EOXML
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
@ -938,12 +978,13 @@ EOXML;
|
|||
$this->DoRequest($this->calendar_url, "REPORT", $body, "text/xml");
|
||||
|
||||
$report = array();
|
||||
foreach( $this->xmlnodes as $k => $v ) {
|
||||
switch( $v['tag'] ) {
|
||||
foreach ($this->xmlnodes as $k => $v) {
|
||||
switch ($v['tag']) {
|
||||
case 'DAV::response':
|
||||
if ( $v['type'] == 'open' ) {
|
||||
if ($v['type'] == 'open') {
|
||||
$response = array();
|
||||
} elseif ( $v['type'] == 'close' ) {
|
||||
}
|
||||
elseif ($v['type'] == 'close') {
|
||||
$report[] = $response;
|
||||
}
|
||||
break;
|
||||
|
@ -966,7 +1007,13 @@ EOXML;
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Report sync-token support on initial sync
|
||||
if ($initial && $support_dav_sync && !isset($this->synctoken[$this->calendar_url])) {
|
||||
ZLog::Write(LOGLEVEL_WARN, 'CalDAVClient->GetSync(): no DAV::sync-token received; did you set CALDAV_SUPPORTS_SYNC correctly?');
|
||||
}
|
||||
|
||||
return $report;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -160,7 +160,7 @@ class carddav_backend
|
|||
*
|
||||
* @var resource
|
||||
*/
|
||||
private $curl;
|
||||
private $curl = false;
|
||||
|
||||
/**
|
||||
* Debug on or off
|
||||
|
@ -546,7 +546,6 @@ EOFXMLGETXMLVCARD;
|
|||
switch($result['http_code']) {
|
||||
case 200:
|
||||
case 207:
|
||||
case 401:
|
||||
$status = true;
|
||||
break;
|
||||
}
|
||||
|
@ -771,7 +770,7 @@ EOFXSL;
|
|||
* @return void
|
||||
*/
|
||||
public function curl_init() {
|
||||
if (empty($this->curl)) {
|
||||
if ($this->curl === false) {
|
||||
$this->curl = curl_init();
|
||||
curl_setopt($this->curl, CURLOPT_HEADER, true);
|
||||
curl_setopt($this->curl, CURLOPT_SSL_VERIFYHOST, false);
|
||||
|
@ -885,8 +884,17 @@ EOFXSL;
|
|||
* @return void
|
||||
*/
|
||||
public function __destruct() {
|
||||
if (!empty($this->curl)) {
|
||||
$this->disconnect();
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnect curl connection
|
||||
*
|
||||
*/
|
||||
public function disconnect() {
|
||||
if ($this->curl !== false) {
|
||||
curl_close($this->curl);
|
||||
$this->curl = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -43,85 +43,29 @@
|
|||
* Consult LICENSE file for details
|
||||
************************************************/
|
||||
|
||||
ob_start(null, 1048576);
|
||||
|
||||
// #190, KD 2015-06-08 - We are missing the flags to truncate the buffer in PHP >= 5.4
|
||||
if (version_compare(phpversion(), '5.4.0') < 0) {
|
||||
ob_start(null, 1048576);
|
||||
}
|
||||
else {
|
||||
ob_start(null, 1048576, PHP_OUTPUT_HANDLER_STDFLAGS);
|
||||
}
|
||||
|
||||
// ignore user abortions because this can lead to weird errors - see ZP-239
|
||||
ignore_user_abort(true);
|
||||
|
||||
include_once('lib/exceptions/exceptions.php');
|
||||
include_once('lib/utils/utils.php');
|
||||
include_once('lib/utils/compat.php');
|
||||
include_once('lib/utils/timezoneutil.php');
|
||||
include_once('lib/core/zpushdefs.php');
|
||||
include_once('lib/core/stateobject.php');
|
||||
include_once('lib/core/interprocessdata.php');
|
||||
include_once('lib/core/pingtracking.php');
|
||||
include_once('lib/core/topcollector.php');
|
||||
include_once('lib/core/loopdetection.php');
|
||||
include_once('lib/core/asdevice.php');
|
||||
include_once('lib/core/statemanager.php');
|
||||
include_once('lib/core/devicemanager.php');
|
||||
include_once('lib/core/zpush.php');
|
||||
include_once('lib/core/zlog.php');
|
||||
include_once('lib/core/paddingfilter.php');
|
||||
include_once('lib/interface/ibackend.php');
|
||||
include_once('lib/interface/ichanges.php');
|
||||
include_once('lib/interface/iexportchanges.php');
|
||||
include_once('lib/interface/iimportchanges.php');
|
||||
include_once('lib/interface/isearchprovider.php');
|
||||
include_once('lib/interface/istatemachine.php');
|
||||
include_once('lib/core/streamer.php');
|
||||
include_once('lib/core/streamimporter.php');
|
||||
include_once('lib/core/synccollections.php');
|
||||
include_once('lib/core/hierarchycache.php');
|
||||
include_once('lib/core/changesmemorywrapper.php');
|
||||
include_once('lib/core/syncparameters.php');
|
||||
include_once('lib/core/bodypreference.php');
|
||||
include_once('lib/core/contentparameters.php');
|
||||
include_once('lib/wbxml/wbxmldefs.php');
|
||||
include_once('lib/wbxml/wbxmldecoder.php');
|
||||
include_once('lib/wbxml/wbxmlencoder.php');
|
||||
include_once('lib/syncobjects/syncobject.php');
|
||||
include_once('lib/syncobjects/syncbasebody.php');
|
||||
include_once('lib/syncobjects/syncbaseattachment.php');
|
||||
include_once('lib/syncobjects/syncmailflags.php');
|
||||
include_once('lib/syncobjects/syncrecurrence.php');
|
||||
include_once('lib/syncobjects/syncappointment.php');
|
||||
include_once('lib/syncobjects/syncappointmentexception.php');
|
||||
include_once('lib/syncobjects/syncattachment.php');
|
||||
include_once('lib/syncobjects/syncattendee.php');
|
||||
include_once('lib/syncobjects/syncmeetingrequestrecurrence.php');
|
||||
include_once('lib/syncobjects/syncmeetingrequest.php');
|
||||
include_once('lib/syncobjects/syncmail.php');
|
||||
include_once('lib/syncobjects/syncnote.php');
|
||||
include_once('lib/syncobjects/synccontact.php');
|
||||
include_once('lib/syncobjects/syncfolder.php');
|
||||
include_once('lib/syncobjects/syncprovisioning.php');
|
||||
include_once('lib/syncobjects/synctaskrecurrence.php');
|
||||
include_once('lib/syncobjects/synctask.php');
|
||||
include_once('lib/syncobjects/syncoofmessage.php');
|
||||
include_once('lib/syncobjects/syncoof.php');
|
||||
include_once('lib/syncobjects/syncuserinformation.php');
|
||||
include_once('lib/syncobjects/syncdeviceinformation.php');
|
||||
include_once('lib/syncobjects/syncdevicepassword.php');
|
||||
include_once('lib/syncobjects/syncitemoperationsattachment.php');
|
||||
include_once('lib/syncobjects/syncsendmail.php');
|
||||
include_once('lib/syncobjects/syncsendmailsource.php');
|
||||
include_once('lib/syncobjects/syncvalidatecert.php');
|
||||
include_once('lib/syncobjects/syncresolverecipients.php');
|
||||
include_once('lib/syncobjects/syncresolverecipient.php');
|
||||
include_once('lib/syncobjects/syncresolverecipientsoptions.php');
|
||||
include_once('lib/syncobjects/syncresolverecipientsavailability.php');
|
||||
include_once('lib/syncobjects/syncresolverecipientscertificates.php');
|
||||
include_once('lib/syncobjects/syncresolverecipientspicture.php');
|
||||
include_once('lib/default/backend.php');
|
||||
include_once('lib/default/searchprovider.php');
|
||||
include_once('lib/request/request.php');
|
||||
include_once('lib/request/requestprocessor.php');
|
||||
|
||||
include_once('config.php');
|
||||
include_once('version.php');
|
||||
require_once 'vendor/autoload.php';
|
||||
require_once 'config.php';
|
||||
|
||||
if (defined('LOG_MEMORY_PROFILER') && LOG_MEMORY_PROFILER) {
|
||||
if (function_exists('memprof_enable')) {
|
||||
memprof_enable();
|
||||
}
|
||||
else {
|
||||
ZLog::Write(LOGLEVEL_WARN, "Memory profiler is enabled but the php-pecl-memprof extension was not found. Install and enable it");
|
||||
}
|
||||
}
|
||||
|
||||
// Attempt to set maximum execution time
|
||||
ini_set('max_execution_time', SCRIPT_TIMEOUT);
|
||||
|
@ -206,43 +150,24 @@ include_once('version.php');
|
|||
}
|
||||
|
||||
RequestProcessor::Initialize();
|
||||
if(!RequestProcessor::HandleRequest())
|
||||
throw new WBXMLException(ZLog::GetWBXMLDebugInfo());
|
||||
RequestProcessor::HandleRequest();
|
||||
|
||||
// eventually the RequestProcessor wants to send other headers to the mobile
|
||||
foreach (RequestProcessor::GetSpecialHeaders() as $header)
|
||||
header($header);
|
||||
|
||||
// stream the data
|
||||
$len = ob_get_length();
|
||||
$data = ob_get_contents();
|
||||
ob_end_clean();
|
||||
|
||||
// log amount of data transferred
|
||||
// TODO check $len when streaming more data (e.g. Attachments), as the data will be send chunked
|
||||
ZPush::GetDeviceManager()->SentData($len);
|
||||
|
||||
// Unfortunately, even though Z-Push can stream the data to the client
|
||||
// with a chunked encoding, using chunked encoding breaks the progress bar
|
||||
// on the PDA. So the data is de-chunk here, written a content-length header and
|
||||
// data send as a 'normal' packet. If the output packet exceeds 1MB (see ob_start)
|
||||
// then it will be sent as a chunked packet anyway because PHP will have to flush
|
||||
// the buffer.
|
||||
if(!headers_sent())
|
||||
header("Content-Length: $len");
|
||||
|
||||
// send vnd.ms-sync.wbxml content type header if there is no content
|
||||
// otherwise text/html content type is added which might break some devices
|
||||
if ($len == 0)
|
||||
header("Content-Type: application/vnd.ms-sync.wbxml");
|
||||
|
||||
print $data;
|
||||
|
||||
// destruct backend after all data is on the stream
|
||||
$backend->Logoff();
|
||||
ZPush::GetDeviceManager()->SentData(ob_get_length());
|
||||
}
|
||||
|
||||
catch (NoPostRequestException $nopostex) {
|
||||
$len = ob_get_length();
|
||||
if ($len) {
|
||||
ZLog::Write(LOGLEVEL_WARN, sprintf("Cleaning %d octets of data", $len));
|
||||
ob_clean();
|
||||
}
|
||||
|
||||
if ($nopostex->getCode() == NoPostRequestException::OPTIONS_REQUEST) {
|
||||
header(ZPush::GetServerHeader());
|
||||
header(ZPush::GetSupportedProtocolVersions());
|
||||
|
@ -258,6 +183,12 @@ include_once('version.php');
|
|||
}
|
||||
|
||||
catch (Exception $ex) {
|
||||
$len = ob_get_length();
|
||||
if ($len) {
|
||||
ZLog::Write(LOGLEVEL_WARN, sprintf("Cleaning %d octets of data", $len));
|
||||
ob_clean();
|
||||
}
|
||||
|
||||
if (Request::GetUserAgent())
|
||||
ZLog::Write(LOGLEVEL_INFO, sprintf("User-agent: '%s'", Request::GetUserAgent()));
|
||||
$exclass = get_class($ex);
|
||||
|
@ -285,7 +216,7 @@ include_once('version.php');
|
|||
|
||||
// This could be a WBXML problem.. try to get the complete request
|
||||
else if ($ex instanceof WBXMLException) {
|
||||
ZLog::Write(LOGLEVEL_FATAL, "Request could not be processed correctly due to a WBXMLException. Please report this.");
|
||||
ZLog::Write(LOGLEVEL_FATAL, "Request could not be processed correctly due to a WBXMLException. Please report this including WBXML debug data logged. Be aware that the debug data could contain confidential information.");
|
||||
}
|
||||
|
||||
// Try to output some kind of error information. This is only possible if
|
||||
|
@ -306,10 +237,29 @@ include_once('version.php');
|
|||
ZPush::GetTopCollector()->AnnounceInformation(get_class($ex), true);
|
||||
}
|
||||
|
||||
// FinishResponse
|
||||
ZPush::FinishResponse();
|
||||
// destruct backend after all data is on the stream
|
||||
ZPush::GetBackend()->Logoff();
|
||||
|
||||
// save device data if the DeviceManager is available
|
||||
if (ZPush::GetDeviceManager(false))
|
||||
ZPush::GetDeviceManager()->Save();
|
||||
|
||||
// end gracefully
|
||||
ZLog::Write(LOGLEVEL_DEBUG, '-------- End');
|
||||
?>
|
||||
if (version_compare(phpversion(), '5.4.0') < 0) {
|
||||
$time_used = number_format(time() - $_SERVER["REQUEST_TIME"], 4);
|
||||
}
|
||||
else {
|
||||
$time_used = number_format(microtime(true) - $_SERVER["REQUEST_TIME_FLOAT"], 4);
|
||||
}
|
||||
|
||||
ZLog::Write(LOGLEVEL_DEBUG, sprintf("-------- End - max mem: %s/%s - time: %s - code: %s", memory_get_peak_usage(false), memory_get_peak_usage(true), $time_used, http_response_code()));
|
||||
|
||||
|
||||
if (defined('LOG_MEMORY_PROFILER') && LOG_MEMORY_PROFILER) {
|
||||
if (function_exists('memprof_enable')) {
|
||||
// Be aware that the pid is not unique, so we will overwrite the output in some cases. But using the pid will be easier to relate the dump with the log lines
|
||||
memprof_dump_callgrind(fopen(LOG_MEMORY_PROFILER_FILE . "_" . getmypid(), "w"));
|
||||
}
|
||||
}
|
|
@ -687,5 +687,3 @@ class ASDevice extends StateObject {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
|
@ -65,4 +65,3 @@ class BodyPreference extends StateObject {
|
|||
return (count($this->data) > 0);
|
||||
}
|
||||
}
|
||||
?>
|
|
@ -115,7 +115,6 @@ class ChangesMemoryWrapper extends HierarchyCache implements IImportChanges, IEx
|
|||
public function LoadConflicts($contentparameters, $state) { return true; }
|
||||
public function ConfigContentParameters($contentparameters) { return true; }
|
||||
public function ImportMessageReadFlag($id, $flags) { return true; }
|
||||
public function ImportMessageStarFlag($id, $flags) { return true; }
|
||||
public function ImportMessageMove($id, $newfolder) { return true; }
|
||||
|
||||
/**----------------------------------------------------------------------------------------------------------
|
||||
|
@ -346,5 +345,3 @@ class ChangesMemoryWrapper extends HierarchyCache implements IImportChanges, IEx
|
|||
$this->step = 0;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -137,5 +137,3 @@ class ContentParameters extends StateObject {
|
|||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -91,7 +91,7 @@ class DeviceManager {
|
|||
else
|
||||
throw new FatalNotImplementedException("Can not proceed without a device id.");
|
||||
|
||||
$this->loopdetection = new LoopDetection();
|
||||
$this->loopdetection = ZPush::GetLoopDetection();
|
||||
$this->loopdetection->ProcessLoopDetectionInit();
|
||||
$this->loopdetection->ProcessLoopDetectionPreviousConnectionFailed();
|
||||
|
||||
|
@ -427,6 +427,8 @@ class DeviceManager {
|
|||
return true;
|
||||
}
|
||||
|
||||
if (!is_object($message))
|
||||
throw new Exception("DeviceManager->DoNotStreamMessage(): message isn't an object");
|
||||
// message is semantically incorrect
|
||||
if (!$message->Check(true)) {
|
||||
$this->AnnounceIgnoredMessage($folderid, $id, $message, self::MSG_BROKEN_SEMANTICERR);
|
||||
|
@ -478,7 +480,7 @@ class DeviceManager {
|
|||
|
||||
if (defined("SYNC_MAX_ITEMS") && SYNC_MAX_ITEMS < $items) {
|
||||
if ($queuedmessages > SYNC_MAX_ITEMS)
|
||||
ZLog::Write(LOGLEVEL_DEBUG, sprintf("DeviceManager->GetWindowSize() overwriting max itmes requested of %d by %d forced in configuration.", $items, SYNC_MAX_ITEMS));
|
||||
ZLog::Write(LOGLEVEL_DEBUG, sprintf("DeviceManager->GetWindowSize() overwriting max items requested of %d by %d forced in configuration.", $items, SYNC_MAX_ITEMS));
|
||||
$items = SYNC_MAX_ITEMS;
|
||||
}
|
||||
|
||||
|
@ -899,5 +901,3 @@ class DeviceManager {
|
|||
return $this->latestFolder;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -212,5 +212,3 @@ class HierarchyCache {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
|
@ -1,101 +0,0 @@
|
|||
<?php
|
||||
/***********************************************
|
||||
* File : paddingfilter.php
|
||||
* Project : Z-Push
|
||||
* Descr : Our own filter for stream padding with zero strings.
|
||||
*
|
||||
* Created : 18.07.2012
|
||||
*
|
||||
* Copyright 2007 - 2013 Zarafa Deutschland GmbH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation with the following additional
|
||||
* term according to sec. 7:
|
||||
*
|
||||
* According to sec. 7 of the GNU Affero General Public License, version 3,
|
||||
* the terms of the AGPL are supplemented with the following terms:
|
||||
*
|
||||
* "Zarafa" is a registered trademark of Zarafa B.V.
|
||||
* "Z-Push" is a registered trademark of Zarafa Deutschland GmbH
|
||||
* The licensing of the Program under the AGPL does not imply a trademark license.
|
||||
* Therefore any rights, title and interest in our trademarks remain entirely with us.
|
||||
*
|
||||
* However, if you propagate an unmodified version of the Program you are
|
||||
* allowed to use the term "Z-Push" to indicate that you distribute the Program.
|
||||
* Furthermore you may use our trademarks where it is necessary to indicate
|
||||
* the intended purpose of a product or service provided you use it in accordance
|
||||
* with honest practices in industrial or commercial matters.
|
||||
* If you want to propagate modified versions of the Program under the name "Z-Push",
|
||||
* you may only do so if you have a written permission by Zarafa Deutschland GmbH
|
||||
* (to acquire a permission please contact Zarafa at trademark@zarafa.com).
|
||||
*
|
||||
* 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/>.
|
||||
*
|
||||
* Consult LICENSE file for details
|
||||
************************************************/
|
||||
|
||||
/* Define our filter class
|
||||
*
|
||||
* Usage: stream_filter_append($stream, 'padding.X');
|
||||
* where X is a number a stream will be padded to be
|
||||
* multiple of (e.g. padding.3 will pad the stream
|
||||
* to be multiple of 3 which is useful in base64
|
||||
* encoding).
|
||||
*
|
||||
* */
|
||||
class padding_filter extends php_user_filter {
|
||||
private $padding = 4; // default padding
|
||||
|
||||
/**
|
||||
* This method is called whenever data is read from or written to the attached stream
|
||||
*
|
||||
* @see php_user_filter::filter()
|
||||
*
|
||||
* @param resource $in
|
||||
* @param resource $out
|
||||
* @param int $consumed
|
||||
* @param boolean $closing
|
||||
*
|
||||
* @access public
|
||||
* @return int
|
||||
*
|
||||
*/
|
||||
function filter($in, $out, &$consumed, $closing) {
|
||||
while ($bucket = stream_bucket_make_writeable($in)) {
|
||||
if ($this->padding != 0 && $bucket->datalen < 8192) {
|
||||
$bucket->data .= str_pad($bucket->data, $this->padding, 0x0);
|
||||
}
|
||||
$consumed += ($this->padding != 0 && $bucket->datalen < 8192) ? ($bucket->datalen + $this->padding) : $bucket->datalen;
|
||||
stream_bucket_append($out, $bucket);
|
||||
}
|
||||
return PSFS_PASS_ON;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when creating the filter
|
||||
*
|
||||
* @see php_user_filter::onCreate()
|
||||
*
|
||||
* @access public
|
||||
* @return boolean
|
||||
*/
|
||||
function onCreate() {
|
||||
$delim = strrpos($this->filtername, '.');
|
||||
if ($delim !== false) {
|
||||
$padding = substr($this->filtername, $delim + 1);
|
||||
if (is_numeric($padding))
|
||||
$this->padding = $padding;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
stream_filter_register("padding.*", "padding_filter");
|
||||
?>
|
|
@ -316,8 +316,8 @@ class StateManager {
|
|||
*/
|
||||
public function SetBackendStorage($data, $type = self::BACKENDSTORAGE_PERMANENT) {
|
||||
if ($type == self::BACKENDSTORAGE_STATE) {
|
||||
if (!$this->uuid)
|
||||
throw new StateNotYetAvailableException();
|
||||
if (!$this->uuid)
|
||||
throw new StateNotYetAvailableException();
|
||||
|
||||
// TODO serialization should be done in the StateMachine
|
||||
return $this->statemachine->SetState($data, $this->device->GetDeviceId(), IStateMachine::BACKENDSTORAGE, $this->uuid, $this->newStateCounter);
|
||||
|
@ -537,4 +537,3 @@ class StateManager {
|
|||
mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ) );
|
||||
}
|
||||
}
|
||||
?>
|
|
@ -197,7 +197,7 @@ class StateObject implements Serializable {
|
|||
return true;
|
||||
}
|
||||
|
||||
throw new FatalNotImplementedException(sprintf("StateObject->__call('%s'): not implemented. op: {$operator} args:". count($arguments), $name));
|
||||
throw new FatalNotImplementedException(sprintf("StateObject->__call('%s'): not implemented. op: {%s} args: %d", $name, $operator, count($arguments)));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -264,5 +264,3 @@ class StateObject implements Serializable {
|
|||
throw new StateInvalidException("Unserialization failed as class was not found or not compatible");
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -291,7 +291,7 @@ class Streamer implements Serializable {
|
|||
if ($encoder->getMultipart() && isset($map[self::STREAMER_PROP]) && $map[self::STREAMER_PROP] == self::STREAMER_TYPE_MULTIPART) {
|
||||
$encoder->addBodypartStream($this->$map[self::STREAMER_VAR]);
|
||||
$encoder->startTag(SYNC_ITEMOPERATIONS_PART);
|
||||
$encoder->content(count($encoder->getBodypartsCount()));
|
||||
$encoder->content($encoder->getBodypartsCount());
|
||||
$encoder->endTag();
|
||||
continue;
|
||||
}
|
||||
|
@ -315,22 +315,10 @@ class Streamer implements Serializable {
|
|||
$encoder->content(strtoupper(bin2hex($this->$map[self::STREAMER_VAR])));
|
||||
}
|
||||
else if(isset($map[self::STREAMER_TYPE]) && $map[self::STREAMER_TYPE] == self::STREAMER_TYPE_STREAM) {
|
||||
//encode stream with base64
|
||||
$stream = $this->$map[self::STREAMER_VAR];
|
||||
$stat = fstat($stream);
|
||||
// the padding size muss be calculated for the entire stream,
|
||||
// the base64 filter seems to process 8192 byte chunks correctly itself
|
||||
$padding = (isset($stat['size']) && $stat['size'] > 8192) ? ($stat['size'] % 3) : 0;
|
||||
|
||||
$paddingfilter = stream_filter_append($stream, 'padding.'.$padding);
|
||||
$base64filter = stream_filter_append($stream, 'convert.base64-encode');
|
||||
$d = "";
|
||||
while (!feof($stream)) {
|
||||
$d .= fgets($stream, 4096);
|
||||
}
|
||||
$encoder->content($d);
|
||||
stream_filter_remove($base64filter);
|
||||
stream_filter_remove($paddingfilter);
|
||||
//we need to encode in base64
|
||||
$encoder->content(Utils::EncodeBase64($this->$map[self::STREAMER_VAR]));
|
||||
//memory ...
|
||||
$this->$map[self::STREAMER_VAR] = null;
|
||||
}
|
||||
// implode comma or semicolon arrays into a string
|
||||
else if(isset($map[self::STREAMER_TYPE]) && is_array($this->$map[self::STREAMER_VAR]) &&
|
||||
|
@ -461,5 +449,3 @@ class Streamer implements Serializable {
|
|||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -44,6 +44,7 @@
|
|||
class ImportChangesStream implements IImportChanges {
|
||||
private $encoder;
|
||||
private $objclass;
|
||||
private $classAsString;
|
||||
private $seenObjects;
|
||||
private $importedMsgs;
|
||||
private $checkForIgnoredMessages;
|
||||
|
@ -189,41 +190,6 @@ class ImportChangesStream implements IImportChanges {
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Imports a change in 'star' flag
|
||||
* Can only be applied to SyncMail (Email) requests
|
||||
*
|
||||
* @param string $id
|
||||
* @param int $flags - flagged/unflagged
|
||||
*
|
||||
* @access public
|
||||
* @return boolean
|
||||
*/
|
||||
public function ImportMessageStarFlag($id, $flags) {
|
||||
if(!($this->objclass instanceof SyncMail))
|
||||
return false;
|
||||
|
||||
$this->importedMsgs++;
|
||||
|
||||
$this->encoder->startTag(SYNC_MODIFY);
|
||||
$this->encoder->startTag(SYNC_SERVERENTRYID);
|
||||
$this->encoder->content($id);
|
||||
$this->encoder->endTag();
|
||||
$this->encoder->startTag(SYNC_DATA);
|
||||
$this->encoder->startTag(SYNC_POOMMAIL_FLAG);
|
||||
$this->encoder->startTag(SYNC_POOMMAIL_FLAGSTATUS);
|
||||
$this->encoder->content($flags == 1? "2" : "0");
|
||||
$this->encoder->endTag();
|
||||
$this->encoder->startTag(SYNC_POOMMAIL_FLAGTYPE);
|
||||
$this->encoder->content("FollowUp");
|
||||
$this->encoder->endTag();
|
||||
$this->encoder->endTag();
|
||||
$this->encoder->endTag();
|
||||
$this->encoder->endTag();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* ImportMessageMove is not implemented, as this operation can not be streamed to a WBXMLEncoder
|
||||
*
|
||||
|
@ -293,4 +259,3 @@ class ImportChangesStream implements IImportChanges {
|
|||
return $this->importedMsgs;
|
||||
}
|
||||
}
|
||||
?>
|
|
@ -54,6 +54,7 @@ class SyncCollections implements Iterator {
|
|||
const ERROR_NO_COLLECTIONS = 1;
|
||||
const ERROR_WRONG_HIERARCHY = 2;
|
||||
const OBSOLETE_CONNECTION = 3;
|
||||
const HIERARCHY_CHANGED = 4;
|
||||
|
||||
private $stateManager;
|
||||
|
||||
|
@ -220,7 +221,7 @@ class SyncCollections implements Iterator {
|
|||
|
||||
$this->collections[$spa->GetFolderId()] = $spa;
|
||||
|
||||
ZLog::Write(LOGLEVEL_DEBUG, sprintf("SyncCollections->AddCollection(): Folder id '%s' : ref. PolicyKey '%s', ref. Lifetime '%s', last sync at '%s'", $spa->GetFolderId(), $spa->GetReferencePolicyKey(), $spa->GetReferenceLifetime(), $spa->GetLastSyncTime()));
|
||||
ZLog::Write(LOGLEVEL_DEBUG, sprintf("SyncCollections->AddCollection(): Folder id '%s' : ref. PolicyKey '%s', ref. Lifetime '%s', last sync at '%s'", $spa->GetFolderId(), $spa->GetReferencePolicyKey(), $spa->GetReferenceLifetime(), $spa->GetLastSyncTime()));
|
||||
if ($spa->HasLastSyncTime() && $spa->GetLastSyncTime() > $this->lastSyncTime) {
|
||||
$this->lastSyncTime = $spa->GetLastSyncTime();
|
||||
|
||||
|
@ -232,7 +233,7 @@ class SyncCollections implements Iterator {
|
|||
if ($spa->HasReferenceLifetime())
|
||||
$this->refLifetime = $spa->GetReferenceLifetime();
|
||||
|
||||
ZLog::Write(LOGLEVEL_DEBUG, sprintf("SyncCollections->AddCollection(): Updated reference PolicyKey '%s', reference Lifetime '%s', Last sync at '%s'", $this->refPolicyKey, $this->refLifetime, $this->lastSyncTime));
|
||||
ZLog::Write(LOGLEVEL_DEBUG, sprintf("SyncCollections->AddCollection(): Updated reference PolicyKey '%s', reference Lifetime '%s', Last sync at '%s'", $this->refPolicyKey, $this->refLifetime, $this->lastSyncTime));
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -419,7 +420,7 @@ class SyncCollections implements Iterator {
|
|||
else
|
||||
$checkClasses = implode(" ", array_keys($classes));
|
||||
|
||||
$pingTracking = new PingTracking();
|
||||
$pingTracking = ZPush::GetPingTracking();
|
||||
$this->changes = array();
|
||||
$changesAvailable = false;
|
||||
|
||||
|
@ -473,7 +474,7 @@ class SyncCollections implements Iterator {
|
|||
|
||||
// Check if a hierarchy sync is necessary
|
||||
if (ZPush::GetDeviceManager()->IsHierarchySyncRequired())
|
||||
throw new StatusException("SyncCollections->CheckForChanges(): HierarchySync required.", self::ERROR_WRONG_HIERARCHY);
|
||||
throw new StatusException("SyncCollections->CheckForChanges(): HierarchySync required.", self::HIERARCHY_CHANGED);
|
||||
|
||||
// Check if there are newer requests
|
||||
// If so, this process should be terminated if more than 60 secs to go
|
||||
|
@ -717,5 +718,3 @@ class SyncCollections implements Iterator {
|
|||
$this->stateManager = ZPush::GetDeviceManager()->GetStateManager();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -269,7 +269,7 @@ class SyncParameters extends StateObject {
|
|||
ZLog::Write(LOGLEVEL_DEBUG, "SyncParameters->UseCPO(): removed existing DEFAULT CPO as it is obsolete");
|
||||
}
|
||||
|
||||
ZLOG::Write(LOGLEVEL_DEBUG, sprintf("SyncParameters->UseCPO('%s')", $options));
|
||||
ZLog::Write(LOGLEVEL_DEBUG, sprintf("SyncParameters->UseCPO('%s')", $options));
|
||||
$this->currentCPO = $options;
|
||||
$this->checkCPO($this->currentCPO);
|
||||
}
|
||||
|
@ -347,8 +347,6 @@ class SyncParameters extends StateObject {
|
|||
elseif (isset($this->contentParameters[self::TASKOPTIONS]))
|
||||
$returnCPO = self::TASKOPTIONS;
|
||||
|
||||
if ($returnCPO != $options)
|
||||
ZLog::Write(LOGLEVEL_DEBUG, sprintf("SyncParameters->normalizeType(): using %s for requested %s", $returnCPO, $options));
|
||||
return $returnCPO;
|
||||
}
|
||||
// something unexpected happened, just return default, empty in the worst case
|
||||
|
@ -410,10 +408,10 @@ class SyncParameters extends StateObject {
|
|||
* @return boolean
|
||||
*/
|
||||
protected function postUnserialize() {
|
||||
// init with default options
|
||||
$this->UseCPO();
|
||||
// init with the available CPO or default
|
||||
$availableCPO = $this->normalizeType(self::DEFAULTOPTIONS);
|
||||
$this->UseCPO($availableCPO);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
?>
|
|
@ -50,6 +50,7 @@ class ZLog {
|
|||
static private $lastLogs = array();
|
||||
static private $userLog = false;
|
||||
static private $unAuthCache = array();
|
||||
static private $syslogEnabled = false;
|
||||
|
||||
/**
|
||||
* Initializes the logging
|
||||
|
@ -60,6 +61,11 @@ class ZLog {
|
|||
static public function Initialize() {
|
||||
global $specialLogUsers;
|
||||
|
||||
if (defined('LOG_SYSLOG_ENABLED') && LOG_SYSLOG_ENABLED) {
|
||||
self::$syslogEnabled = true;
|
||||
ZSyslog::Initialize();
|
||||
}
|
||||
|
||||
// define some constants for the logging
|
||||
if (!defined('LOGUSERLEVEL'))
|
||||
define('LOGUSERLEVEL', LOGLEVEL_OFF);
|
||||
|
@ -111,7 +117,7 @@ class ZLog {
|
|||
$data = self::buildLogString($loglevel) . $message . "\n";
|
||||
|
||||
if ($loglevel <= LOGLEVEL) {
|
||||
@file_put_contents(LOGFILE, $data, FILE_APPEND);
|
||||
self::writeToLog($loglevel, $data, LOGFILE);
|
||||
}
|
||||
|
||||
// should we write this into the user log?
|
||||
|
@ -123,11 +129,11 @@ class ZLog {
|
|||
if (self::logToUserFile()) {
|
||||
// something was logged before the user was authenticated, write this to the log
|
||||
if (!empty(self::$unAuthCache)) {
|
||||
@file_put_contents(LOGFILEDIR . self::logToUserFile() . ".log", implode('', self::$unAuthCache), FILE_APPEND);
|
||||
self::writeToLog($loglevel, implode('', self::$unAuthCache), LOGFILEDIR . self::logToUserFile() . ".log");
|
||||
self::$unAuthCache = array();
|
||||
}
|
||||
// only use plain old a-z characters for the generic log file
|
||||
@file_put_contents(LOGFILEDIR . self::logToUserFile() . ".log", $data, FILE_APPEND);
|
||||
self::writeToLog($loglevel, $data, LOGFILEDIR . self::logToUserFile() . ".log");
|
||||
}
|
||||
// the user is not authenticated yet, we save the log into memory for now
|
||||
else {
|
||||
|
@ -136,7 +142,7 @@ class ZLog {
|
|||
}
|
||||
|
||||
if (($loglevel & LOGLEVEL_FATAL) || ($loglevel & LOGLEVEL_ERROR)) {
|
||||
@file_put_contents(LOGERRORFILE, $data, FILE_APPEND);
|
||||
self::writeToLog($loglevel, $data, LOGERRORFILE);
|
||||
}
|
||||
|
||||
if ($loglevel & LOGLEVEL_WBXMLSTACK) {
|
||||
|
@ -205,7 +211,10 @@ class ZLog {
|
|||
if (!isset(self::$devid))
|
||||
self::$devid = '';
|
||||
|
||||
return Utils::GetFormattedTime() ." ". self::$pidstr . self::getLogLevelString($loglevel, (LOGLEVEL > LOGLEVEL_INFO)) ." ". self::$user . self::$devid;
|
||||
if (self::$syslogEnabled)
|
||||
return self::$pidstr . self::getLogLevelString($loglevel, (LOGLEVEL > LOGLEVEL_INFO)) . " " . self::$user . self::$devid;
|
||||
else
|
||||
return Utils::GetFormattedTime() . " " . self::$pidstr . self::getLogLevelString($loglevel, (LOGLEVEL > LOGLEVEL_INFO)) . " " . self::$user . self::$devid;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -233,48 +242,29 @@ class ZLog {
|
|||
case LOGLEVEL_WBXMLSTACK: return "[WBXMLSTACK]"; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**----------------------------------------------------------------------------------------------------------
|
||||
* Legacy debug stuff
|
||||
*/
|
||||
|
||||
// deprecated
|
||||
// backwards compatible
|
||||
function debugLog($message) {
|
||||
ZLog::Write(LOGLEVEL_DEBUG, $message);
|
||||
}
|
||||
|
||||
// TODO review error handler
|
||||
function zarafa_error_handler($errno, $errstr, $errfile, $errline, $errcontext) {
|
||||
$bt = debug_backtrace();
|
||||
switch ($errno) {
|
||||
case 8192: // E_DEPRECATED since PHP 5.3.0
|
||||
// do not handle this message
|
||||
break;
|
||||
|
||||
case E_NOTICE:
|
||||
case E_WARNING:
|
||||
// TODO check if there is a better way to avoid these messages
|
||||
if (stripos($errfile,'interprocessdata') !== false && stripos($errstr,'shm_get_var()') !== false)
|
||||
break;
|
||||
ZLog::Write(LOGLEVEL_WARN, "$errfile:$errline $errstr ($errno)");
|
||||
break;
|
||||
|
||||
default:
|
||||
ZLog::Write(LOGLEVEL_ERROR, "trace error: $errfile:$errline $errstr ($errno) - backtrace: ". (count($bt)-1) . " steps");
|
||||
for($i = 1, $bt_length = count($bt); $i < $bt_length; $i++) {
|
||||
$file = $line = "unknown";
|
||||
if (isset($bt[$i]['file'])) $file = $bt[$i]['file'];
|
||||
if (isset($bt[$i]['line'])) $line = $bt[$i]['line'];
|
||||
ZLog::Write(LOGLEVEL_ERROR, "trace: $i:". $file . ":" . $line. " - " . ((isset($bt[$i]['class']))? $bt[$i]['class'] . $bt[$i]['type']:""). $bt[$i]['function']. "()");
|
||||
/**
|
||||
* Write the message to the log facility.
|
||||
*
|
||||
* @param int $loglevel
|
||||
* @param string $data
|
||||
* @param string $logfile
|
||||
*
|
||||
* @access private
|
||||
* @return void
|
||||
*/
|
||||
static private function writeToLog($loglevel, $data, $logfile = null) {
|
||||
if (self::$syslogEnabled) {
|
||||
if (ZSyslog::send($loglevel, $data) === false) {
|
||||
error_log("Unable to send to syslog");
|
||||
error_log($data);
|
||||
}
|
||||
//throw new Exception("An error occured.");
|
||||
break;
|
||||
}
|
||||
else {
|
||||
if (@file_put_contents($logfile, $data, FILE_APPEND) === false) {
|
||||
error_log(sprintf("Unable to write in %s", $logfile));
|
||||
error_log($data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
error_reporting(E_ALL);
|
||||
set_error_handler("zarafa_error_handler");
|
||||
|
||||
?>
|
73
sources/lib/core/zpush-utils.php
Normal file
73
sources/lib/core/zpush-utils.php
Normal file
|
@ -0,0 +1,73 @@
|
|||
<?php
|
||||
|
||||
// TODO Win1252/UTF8 functions are deprecated and will be removed sometime
|
||||
//if the ICS backend is loaded in CombinedBackend and Zarafa > 7
|
||||
//STORE_SUPPORTS_UNICODE is true and the convertion will not be done
|
||||
//for other backends.
|
||||
function utf8_to_windows1252($string, $option = "", $force_convert = false) {
|
||||
//if the store supports unicode return the string without converting it
|
||||
if (!$force_convert && defined('STORE_SUPPORTS_UNICODE') && STORE_SUPPORTS_UNICODE == true) return $string;
|
||||
|
||||
if (function_exists("iconv")){
|
||||
return @iconv("UTF-8", "Windows-1252" . $option, $string);
|
||||
}else{
|
||||
return utf8_decode($string); // no euro support here
|
||||
}
|
||||
}
|
||||
|
||||
function windows1252_to_utf8($string, $option = "", $force_convert = false) {
|
||||
//if the store supports unicode return the string without converting it
|
||||
if (!$force_convert && defined('STORE_SUPPORTS_UNICODE') && STORE_SUPPORTS_UNICODE == true) return $string;
|
||||
|
||||
if (function_exists("iconv")){
|
||||
return @iconv("Windows-1252", "UTF-8" . $option, $string);
|
||||
}else{
|
||||
return utf8_encode($string); // no euro support here
|
||||
}
|
||||
}
|
||||
|
||||
function w2u($string) { return windows1252_to_utf8($string); }
|
||||
function u2w($string) { return utf8_to_windows1252($string); }
|
||||
|
||||
function w2ui($string) { return windows1252_to_utf8($string, "//TRANSLIT"); }
|
||||
function u2wi($string) { return utf8_to_windows1252($string, "//TRANSLIT"); }
|
||||
|
||||
/**
|
||||
* @param string $message
|
||||
* @deprecated
|
||||
*/
|
||||
function debugLog($message) {
|
||||
ZLog::Write(LOGLEVEL_DEBUG, $message);
|
||||
}
|
||||
|
||||
// TODO review error handler
|
||||
function zarafa_error_handler($errno, $errstr, $errfile, $errline, $errcontext) {
|
||||
$bt = debug_backtrace();
|
||||
switch ($errno) {
|
||||
case 8192: // E_DEPRECATED since PHP 5.3.0
|
||||
// do not handle this message
|
||||
break;
|
||||
|
||||
case E_NOTICE:
|
||||
case E_WARNING:
|
||||
// TODO check if there is a better way to avoid these messages
|
||||
if (stripos($errfile,'interprocessdata') !== false && stripos($errstr,'shm_get_var()') !== false)
|
||||
break;
|
||||
ZLog::Write(LOGLEVEL_WARN, "$errfile:$errline $errstr ($errno)");
|
||||
break;
|
||||
|
||||
default:
|
||||
ZLog::Write(LOGLEVEL_ERROR, "trace error: $errfile:$errline $errstr ($errno) - backtrace: ". (count($bt)-1) . " steps");
|
||||
for($i = 1, $bt_length = count($bt); $i < $bt_length; $i++) {
|
||||
$file = $line = "unknown";
|
||||
if (isset($bt[$i]['file'])) $file = $bt[$i]['file'];
|
||||
if (isset($bt[$i]['line'])) $line = $bt[$i]['line'];
|
||||
ZLog::Write(LOGLEVEL_ERROR, "trace: $i:". $file . ":" . $line. " - " . ((isset($bt[$i]['class']))? $bt[$i]['class'] . $bt[$i]['type']:""). $bt[$i]['function']. "()");
|
||||
}
|
||||
//throw new Exception("An error occured.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
error_reporting(E_ALL);
|
||||
set_error_handler("zarafa_error_handler");
|
|
@ -56,13 +56,11 @@ class ZPush {
|
|||
const CLASS_OTHERTYPES = 4;
|
||||
|
||||
// AS versions
|
||||
const ASV_1 = "1.0";
|
||||
const ASV_2 = "2.0";
|
||||
const ASV_21 = "2.1";
|
||||
const ASV_25 = "2.5";
|
||||
const ASV_12 = "12.0";
|
||||
const ASV_121 = "12.1";
|
||||
const ASV_14 = "14.0";
|
||||
const ASV_141 = "14.1";
|
||||
|
||||
/**
|
||||
* Command codes for base64 encoded requests (AS >= 12.1)
|
||||
|
@ -87,12 +85,8 @@ class ZPush {
|
|||
const COMMAND_RESOLVERECIPIENTS = 21;
|
||||
const COMMAND_VALIDATECERT = 22;
|
||||
|
||||
// Deprecated commands
|
||||
// Deprecated commands (AS >= 14)
|
||||
const COMMAND_GETHIERARCHY = -1;
|
||||
const COMMAND_CREATECOLLECTION = -2;
|
||||
const COMMAND_DELETECOLLECTION = -3;
|
||||
const COMMAND_MOVECOLLECTION = -4;
|
||||
const COMMAND_NOTIFY = -5;
|
||||
|
||||
// Webservice commands
|
||||
const COMMAND_WEBSERVICE_DEVICE = -100;
|
||||
|
@ -109,48 +103,68 @@ class ZPush {
|
|||
"BackendMaildir"
|
||||
);
|
||||
|
||||
// Versions 1.0, 2.0, 2.1 and 2.5 are deprecated (ZP-604)
|
||||
static private $supportedASVersions = array(
|
||||
self::ASV_1,
|
||||
self::ASV_2,
|
||||
self::ASV_21,
|
||||
self::ASV_25,
|
||||
self::ASV_12,
|
||||
self::ASV_121,
|
||||
self::ASV_14
|
||||
self::ASV_14,
|
||||
self::ASV_141
|
||||
);
|
||||
|
||||
static private $supportedCommands = array(
|
||||
// COMMAND // AS VERSION // REQUESTHANDLER // OTHER SETTINGS
|
||||
self::COMMAND_SYNC => array(self::ASV_1, self::REQUESTHANDLER => "Sync"),
|
||||
self::COMMAND_SENDMAIL => array(self::ASV_1, self::REQUESTHANDLER => "SendMail"),
|
||||
self::COMMAND_SMARTFORWARD => array(self::ASV_1, self::REQUESTHANDLER => "SendMail"),
|
||||
self::COMMAND_SMARTREPLY => array(self::ASV_1, self::REQUESTHANDLER => "SendMail"),
|
||||
self::COMMAND_GETATTACHMENT => array(self::ASV_1, self::REQUESTHANDLER => "GetAttachment"),
|
||||
self::COMMAND_GETHIERARCHY => array(self::ASV_1, self::REQUESTHANDLER => "GetHierarchy", self::HIERARCHYCOMMAND), // deprecated but implemented
|
||||
self::COMMAND_CREATECOLLECTION => array(self::ASV_1), // deprecated & not implemented
|
||||
self::COMMAND_DELETECOLLECTION => array(self::ASV_1), // deprecated & not implemented
|
||||
self::COMMAND_MOVECOLLECTION => array(self::ASV_1), // deprecated & not implemented
|
||||
self::COMMAND_FOLDERSYNC => array(self::ASV_2, self::REQUESTHANDLER => "FolderSync", self::HIERARCHYCOMMAND),
|
||||
self::COMMAND_FOLDERCREATE => array(self::ASV_2, self::REQUESTHANDLER => "FolderChange", self::HIERARCHYCOMMAND),
|
||||
self::COMMAND_FOLDERDELETE => array(self::ASV_2, self::REQUESTHANDLER => "FolderChange", self::HIERARCHYCOMMAND),
|
||||
self::COMMAND_FOLDERUPDATE => array(self::ASV_2, self::REQUESTHANDLER => "FolderChange", self::HIERARCHYCOMMAND),
|
||||
self::COMMAND_MOVEITEMS => array(self::ASV_1, self::REQUESTHANDLER => "MoveItems"),
|
||||
self::COMMAND_GETITEMESTIMATE => array(self::ASV_1, self::REQUESTHANDLER => "GetItemEstimate"),
|
||||
self::COMMAND_MEETINGRESPONSE => array(self::ASV_1, self::REQUESTHANDLER => "MeetingResponse"),
|
||||
self::COMMAND_RESOLVERECIPIENTS => array(self::ASV_1, self::REQUESTHANDLER => "ResolveRecipients"),
|
||||
self::COMMAND_VALIDATECERT => array(self::ASV_1, self::REQUESTHANDLER => "ValidateCert"),
|
||||
self::COMMAND_PROVISION => array(self::ASV_25, self::REQUESTHANDLER => "Provisioning", self::UNAUTHENTICATED, self::UNPROVISIONED),
|
||||
self::COMMAND_SEARCH => array(self::ASV_1, self::REQUESTHANDLER => "Search"),
|
||||
self::COMMAND_PING => array(self::ASV_2, self::REQUESTHANDLER => "Ping", self::UNPROVISIONED),
|
||||
self::COMMAND_NOTIFY => array(self::ASV_1, self::REQUESTHANDLER => "Notify"), // deprecated & not implemented
|
||||
self::COMMAND_ITEMOPERATIONS => array(self::ASV_12, self::REQUESTHANDLER => "ItemOperations"),
|
||||
self::COMMAND_SETTINGS => array(self::ASV_12, self::REQUESTHANDLER => "Settings"),
|
||||
// COMMAND // AS VERSION // OTHER SETTINGS
|
||||
self::COMMAND_SYNC => array(self::ASV_25),
|
||||
self::COMMAND_SENDMAIL => array(self::ASV_25),
|
||||
self::COMMAND_SMARTFORWARD => array(self::ASV_25),
|
||||
self::COMMAND_SMARTREPLY => array(self::ASV_25),
|
||||
self::COMMAND_GETATTACHMENT => array(self::ASV_25),
|
||||
self::COMMAND_GETHIERARCHY => array(self::ASV_25, self::HIERARCHYCOMMAND), // deprecated (AS >= 14)
|
||||
self::COMMAND_FOLDERSYNC => array(self::ASV_25, self::HIERARCHYCOMMAND),
|
||||
self::COMMAND_FOLDERCREATE => array(self::ASV_25, self::HIERARCHYCOMMAND),
|
||||
self::COMMAND_FOLDERDELETE => array(self::ASV_25, self::HIERARCHYCOMMAND),
|
||||
self::COMMAND_FOLDERUPDATE => array(self::ASV_25, self::HIERARCHYCOMMAND),
|
||||
self::COMMAND_MOVEITEMS => array(self::ASV_25),
|
||||
self::COMMAND_GETITEMESTIMATE => array(self::ASV_25),
|
||||
self::COMMAND_MEETINGRESPONSE => array(self::ASV_25),
|
||||
self::COMMAND_RESOLVERECIPIENTS => array(self::ASV_25),
|
||||
self::COMMAND_VALIDATECERT => array(self::ASV_25),
|
||||
self::COMMAND_PROVISION => array(self::ASV_25, self::UNAUTHENTICATED, self::UNPROVISIONED),
|
||||
self::COMMAND_SEARCH => array(self::ASV_25),
|
||||
self::COMMAND_PING => array(self::ASV_25, self::UNPROVISIONED),
|
||||
self::COMMAND_ITEMOPERATIONS => array(self::ASV_12),
|
||||
self::COMMAND_SETTINGS => array(self::ASV_12),
|
||||
|
||||
self::COMMAND_WEBSERVICE_DEVICE => array(self::REQUESTHANDLER => "Webservice", self::PLAININPUT, self::NOACTIVESYNCCOMMAND, self::WEBSERVICECOMMAND),
|
||||
self::COMMAND_WEBSERVICE_USERS => array(self::REQUESTHANDLER => "Webservice", self::PLAININPUT, self::NOACTIVESYNCCOMMAND, self::WEBSERVICECOMMAND),
|
||||
);
|
||||
self::COMMAND_WEBSERVICE_DEVICE => array(self::PLAININPUT, self::NOACTIVESYNCCOMMAND, self::WEBSERVICECOMMAND),
|
||||
self::COMMAND_WEBSERVICE_USERS => array(self::PLAININPUT, self::NOACTIVESYNCCOMMAND, self::WEBSERVICECOMMAND),
|
||||
);
|
||||
|
||||
|
||||
static private $requestHandler = array(
|
||||
// COMMAND // REQUESTHANDLER
|
||||
self::COMMAND_SYNC => "Sync",
|
||||
self::COMMAND_SENDMAIL => "SendMail",
|
||||
self::COMMAND_SMARTFORWARD => "SendMail",
|
||||
self::COMMAND_SMARTREPLY => "SendMail",
|
||||
self::COMMAND_GETATTACHMENT => "GetAttachment",
|
||||
self::COMMAND_GETHIERARCHY => "GetHierarchy", // deprecated (AS >= 14)
|
||||
self::COMMAND_FOLDERSYNC => "FolderSync",
|
||||
self::COMMAND_FOLDERCREATE => "FolderChange",
|
||||
self::COMMAND_FOLDERDELETE => "FolderChange",
|
||||
self::COMMAND_FOLDERUPDATE => "FolderChange",
|
||||
self::COMMAND_MOVEITEMS => "MoveItems",
|
||||
self::COMMAND_GETITEMESTIMATE => "GetItemEstimate",
|
||||
self::COMMAND_MEETINGRESPONSE => "MeetingResponse",
|
||||
self::COMMAND_RESOLVERECIPIENTS => "ResolveRecipients",
|
||||
self::COMMAND_VALIDATECERT => "ValidateCert",
|
||||
self::COMMAND_PROVISION => "Provisioning",
|
||||
self::COMMAND_SEARCH => "Search",
|
||||
self::COMMAND_PING => "Ping",
|
||||
self::COMMAND_ITEMOPERATIONS => "ItemOperations",
|
||||
self::COMMAND_SETTINGS => "Settings",
|
||||
|
||||
self::COMMAND_WEBSERVICE_DEVICE => "Webservice",
|
||||
self::COMMAND_WEBSERVICE_USERS => "Webservice",
|
||||
);
|
||||
|
||||
static private $classes = array(
|
||||
"Email" => array(
|
||||
|
@ -205,8 +219,8 @@ class ZPush {
|
|||
*/
|
||||
static public function CheckConfig() {
|
||||
// check the php version
|
||||
if (version_compare(phpversion(),'5.1.0') < 0)
|
||||
throw new FatalException("The configured PHP version is too old. Please make sure at least PHP 5.1 is used.");
|
||||
if (version_compare(phpversion(), '5.3.0') < 0)
|
||||
throw new FatalException("The configured PHP version is too old. Please make sure at least PHP 5.3 is used.");
|
||||
|
||||
// some basic checks
|
||||
if (!defined('BASE_PATH'))
|
||||
|
@ -354,18 +368,16 @@ class ZPush {
|
|||
else {
|
||||
// Initialize the default StateMachine
|
||||
if (defined('STATE_MACHINE') && STATE_MACHINE == 'SQL') {
|
||||
include_once('lib/default/sqlstatemachine.php');
|
||||
ZPush::$stateMachine = new SqlStateMachine();
|
||||
}
|
||||
else {
|
||||
include_once('lib/default/filestatemachine.php');
|
||||
ZPush::$stateMachine = new FileStateMachine();
|
||||
}
|
||||
}
|
||||
|
||||
if (ZPush::$stateMachine->GetStateVersion() !== ZPush::GetLatestStateVersion()) {
|
||||
if (class_exists("TopCollector")) self::GetTopCollector()->AnnounceInformation("Run migration script!", true);
|
||||
throw new HTTPReturnCodeException(sprintf("The state version available to the %s is not the latest version - please run the state upgrade script. See release notes for more information.", get_class(ZPush::$stateMachine), 503));
|
||||
throw new HTTPReturnCodeException(sprintf("The state version available to the %s is not the latest version - please run the state upgrade script. See release notes for more information.", get_class(ZPush::$stateMachine)), HTTP_CODE_500);
|
||||
}
|
||||
}
|
||||
return ZPush::$stateMachine;
|
||||
|
@ -403,10 +415,33 @@ class ZPush {
|
|||
* @return object TopCollector
|
||||
*/
|
||||
static public function GetTopCollector() {
|
||||
if (!isset(ZPush::$topCollector))
|
||||
ZPush::$topCollector = new TopCollector();
|
||||
if (!isset(self::$topCollector)) {
|
||||
$class = defined('TOP_COLLECTOR_BACKEND') ? TOP_COLLECTOR_BACKEND : 'TopCollector';
|
||||
self::$topCollector = new $class();
|
||||
}
|
||||
return self::$topCollector;
|
||||
}
|
||||
|
||||
return ZPush::$topCollector;
|
||||
/**
|
||||
* Returns an instance of PingTracking
|
||||
*
|
||||
* @access public
|
||||
* @return object IPingTracking
|
||||
*/
|
||||
static public function GetPingTracking() {
|
||||
$class = defined('PING_TRACKING_BACKEND') ? PING_TRACKING_BACKEND : 'PingTracking';
|
||||
return new $class();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an instance of LoopDetection
|
||||
*
|
||||
* @access public
|
||||
* @return object ILoopDetection
|
||||
*/
|
||||
static public function GetLoopDetection() {
|
||||
$class = defined('LOOP_DETECTION_BACKEND') ? LOOP_DETECTION_BACKEND : 'LoopDetection';
|
||||
return new $class();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -686,9 +721,7 @@ END;
|
|||
* @return string
|
||||
*/
|
||||
static public function GetSupportedProtocolVersions($valueOnly = false) {
|
||||
//$versions = implode(',', array_slice(self::$supportedASVersions, 0, (array_search(self::GetSupportedASVersion(), self::$supportedASVersions)+1)));
|
||||
// Removing support for AS 1.0, 2.0, 2.1 - That will make Outlook 2013 works
|
||||
$versions = implode(',', array_slice(self::$supportedASVersions, 3, (array_search(self::GetSupportedASVersion(), self::$supportedASVersions)+1)));
|
||||
$versions = implode(',', array_slice(self::$supportedASVersions, 0, (array_search(self::GetSupportedASVersion(), self::$supportedASVersions)+1)));
|
||||
ZLog::Write(LOGLEVEL_DEBUG, "ZPush::GetSupportedProtocolVersions(): " . $versions);
|
||||
|
||||
if ($valueOnly === true)
|
||||
|
@ -725,18 +758,10 @@ END;
|
|||
* @return RequestProcessor sub-class
|
||||
*/
|
||||
static public function GetRequestHandlerForCommand($commandCode) {
|
||||
if (!array_key_exists($commandCode, self::$supportedCommands) ||
|
||||
!array_key_exists(self::REQUESTHANDLER, self::$supportedCommands[$commandCode]) )
|
||||
if (!array_key_exists($commandCode, self::$requestHandler))
|
||||
throw new FatalNotImplementedException(sprintf("Command '%s' has no request handler or class", Utils::GetCommandFromCode($commandCode)));
|
||||
|
||||
$class = self::$supportedCommands[$commandCode][self::REQUESTHANDLER];
|
||||
if ($class == "Webservice")
|
||||
$handlerclass = REAL_BASE_PATH . "lib/webservice/webservice.php";
|
||||
else
|
||||
$handlerclass = REAL_BASE_PATH . "lib/request/" . strtolower($class) . ".php";
|
||||
|
||||
if (is_file($handlerclass))
|
||||
include($handlerclass);
|
||||
$class = self::$requestHandler[$commandCode];
|
||||
|
||||
if (class_exists($class))
|
||||
return new $class();
|
||||
|
@ -830,5 +855,22 @@ END;
|
|||
return $defcapa;
|
||||
}
|
||||
|
||||
/**
|
||||
* End Response
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
public static function FinishResponse() {
|
||||
$len = ob_get_length();
|
||||
if ($len !== false) {
|
||||
if (!headers_sent()) {
|
||||
header(sprintf("Content-Length: %s", $len));
|
||||
if ($len == 0)
|
||||
header("Content-Type:");
|
||||
}
|
||||
ZLog::Write(LOGLEVEL_DEBUG, sprintf("Flushing %d, headers already sent? %s", $len , headers_sent() ? "yes" : "no"));
|
||||
if (!ob_end_flush())
|
||||
ZLog::Write(LOGLEVEL_ERROR, "Unable to flush buffer!?");
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
File diff suppressed because it is too large
Load diff
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue