@@ -8,13 +8,13 @@ |
||
8 | 8 | * to the mobile. |
9 | 9 | */ |
10 | 10 | class HTTPReturnCodeException extends FatalException { |
11 | - protected $defaultLogLevel = LOGLEVEL_ERROR; |
|
12 | - protected $showLegal = false; |
|
11 | + protected $defaultLogLevel = LOGLEVEL_ERROR; |
|
12 | + protected $showLegal = false; |
|
13 | 13 | |
14 | - public function __construct($message = "", $code = 0, $previous = null, $logLevel = false) { |
|
15 | - if ($code) { |
|
16 | - $this->httpReturnCode = $code; |
|
17 | - } |
|
18 | - parent::__construct($message, (int) $code, $previous, $logLevel); |
|
19 | - } |
|
14 | + public function __construct($message = "", $code = 0, $previous = null, $logLevel = false) { |
|
15 | + if ($code) { |
|
16 | + $this->httpReturnCode = $code; |
|
17 | + } |
|
18 | + parent::__construct($message, (int) $code, $previous, $logLevel); |
|
19 | + } |
|
20 | 20 | } |
@@ -15,6 +15,6 @@ |
||
15 | 15 | if ($code) { |
16 | 16 | $this->httpReturnCode = $code; |
17 | 17 | } |
18 | - parent::__construct($message, (int) $code, $previous, $logLevel); |
|
18 | + parent::__construct($message, (int)$code, $previous, $logLevel); |
|
19 | 19 | } |
20 | 20 | } |
@@ -8,7 +8,7 @@ |
||
8 | 8 | * The code indicates if the request identified was a OPTIONS or GET request |
9 | 9 | */ |
10 | 10 | class NoPostRequestException extends FatalException { |
11 | - public const OPTIONS_REQUEST = 1; |
|
12 | - public const GET_REQUEST = 2; |
|
13 | - protected $defaultLogLevel = LOGLEVEL_DEBUG; |
|
11 | + public const OPTIONS_REQUEST = 1; |
|
12 | + public const GET_REQUEST = 2; |
|
13 | + protected $defaultLogLevel = LOGLEVEL_DEBUG; |
|
14 | 14 | } |
@@ -8,16 +8,16 @@ |
||
8 | 8 | */ |
9 | 9 | |
10 | 10 | class ServiceUnavailableException extends HTTPReturnCodeException { |
11 | - protected $defaultLogLevel = LOGLEVEL_INFO; |
|
12 | - protected $httpReturnCode = HTTP_CODE_503; |
|
13 | - protected $httpReturnMessage = "Service Unavailable"; |
|
14 | - protected $httpHeaders = []; |
|
15 | - protected $showLegal = false; |
|
11 | + protected $defaultLogLevel = LOGLEVEL_INFO; |
|
12 | + protected $httpReturnCode = HTTP_CODE_503; |
|
13 | + protected $httpReturnMessage = "Service Unavailable"; |
|
14 | + protected $httpHeaders = []; |
|
15 | + protected $showLegal = false; |
|
16 | 16 | |
17 | - public function __construct($message = "", $code = 0, $previous = null, $logLevel = false) { |
|
18 | - parent::__construct($message, $code, $previous, $logLevel); |
|
19 | - if (RETRY_AFTER_DELAY !== false) { |
|
20 | - $this->httpHeaders[] = 'Retry-After: ' . RETRY_AFTER_DELAY; |
|
21 | - } |
|
22 | - } |
|
17 | + public function __construct($message = "", $code = 0, $previous = null, $logLevel = false) { |
|
18 | + parent::__construct($message, $code, $previous, $logLevel); |
|
19 | + if (RETRY_AFTER_DELAY !== false) { |
|
20 | + $this->httpHeaders[] = 'Retry-After: ' . RETRY_AFTER_DELAY; |
|
21 | + } |
|
22 | + } |
|
23 | 23 | } |
@@ -17,7 +17,7 @@ |
||
17 | 17 | public function __construct($message = "", $code = 0, $previous = null, $logLevel = false) { |
18 | 18 | parent::__construct($message, $code, $previous, $logLevel); |
19 | 19 | if (RETRY_AFTER_DELAY !== false) { |
20 | - $this->httpHeaders[] = 'Retry-After: ' . RETRY_AFTER_DELAY; |
|
20 | + $this->httpHeaders[] = 'Retry-After: '.RETRY_AFTER_DELAY; |
|
21 | 21 | } |
22 | 22 | } |
23 | 23 | } |
@@ -10,29 +10,29 @@ discard block |
||
10 | 10 | /* |
11 | 11 | * Default settings |
12 | 12 | */ |
13 | - // Defines the default time zone, change e.g. to "Europe/London" if necessary |
|
14 | - define('TIMEZONE', ''); |
|
13 | + // Defines the default time zone, change e.g. to "Europe/London" if necessary |
|
14 | + define('TIMEZONE', ''); |
|
15 | 15 | |
16 | - // Defines the base path on the server |
|
17 | - define('BASE_PATH', dirname($_SERVER['SCRIPT_FILENAME']) . '/'); |
|
16 | + // Defines the base path on the server |
|
17 | + define('BASE_PATH', dirname($_SERVER['SCRIPT_FILENAME']) . '/'); |
|
18 | 18 | |
19 | - // Try to set unlimited timeout |
|
20 | - define('SCRIPT_TIMEOUT', 0); |
|
19 | + // Try to set unlimited timeout |
|
20 | + define('SCRIPT_TIMEOUT', 0); |
|
21 | 21 | |
22 | - // This should be solved on THE webserver level if there are proxies |
|
23 | - // between mobile client and grommunio-sync. |
|
24 | - // Use a custom header to determinate the remote IP of a client. |
|
25 | - // By default, the server provided REMOTE_ADDR is used. If the header here set |
|
26 | - // is available, the provided value will be used, else REMOTE_ADDR is maintained. |
|
27 | - // set to false to disable this behaviour. |
|
28 | - // common values: 'HTTP_X_FORWARDED_FOR', 'HTTP_X_REAL_IP' (casing is ignored) |
|
29 | - define('USE_CUSTOM_REMOTE_IP_HEADER', false); |
|
22 | + // This should be solved on THE webserver level if there are proxies |
|
23 | + // between mobile client and grommunio-sync. |
|
24 | + // Use a custom header to determinate the remote IP of a client. |
|
25 | + // By default, the server provided REMOTE_ADDR is used. If the header here set |
|
26 | + // is available, the provided value will be used, else REMOTE_ADDR is maintained. |
|
27 | + // set to false to disable this behaviour. |
|
28 | + // common values: 'HTTP_X_FORWARDED_FOR', 'HTTP_X_REAL_IP' (casing is ignored) |
|
29 | + define('USE_CUSTOM_REMOTE_IP_HEADER', false); |
|
30 | 30 | |
31 | - // When using client certificates, we can check if the login sent matches the owner of the certificate. |
|
32 | - // This setting specifies the owner parameter in the certificate to look at. |
|
33 | - define("CERTIFICATE_OWNER_PARAMETER", "SSL_CLIENT_S_DN_CN"); |
|
31 | + // When using client certificates, we can check if the login sent matches the owner of the certificate. |
|
32 | + // This setting specifies the owner parameter in the certificate to look at. |
|
33 | + define("CERTIFICATE_OWNER_PARAMETER", "SSL_CLIENT_S_DN_CN"); |
|
34 | 34 | |
35 | - /* |
|
35 | + /* |
|
36 | 36 | * Whether to use the complete email address as a login name |
37 | 37 | * (e.g. [email protected]) or the username only (user). |
38 | 38 | * This is required for grommunio-sync to work properly after autodiscover. |
@@ -40,7 +40,7 @@ discard block |
||
40 | 40 | * false - use the username only. |
41 | 41 | * true - string the mobile sends as username, e.g. full email address (default). |
42 | 42 | */ |
43 | - define('USE_FULLEMAIL_FOR_LOGIN', true); |
|
43 | + define('USE_FULLEMAIL_FOR_LOGIN', true); |
|
44 | 44 | |
45 | 45 | /* |
46 | 46 | * Logging settings |
@@ -67,189 +67,189 @@ discard block |
||
67 | 67 | * |
68 | 68 | * LOGAUTHFAIL is logged to the LOGBACKEND. |
69 | 69 | */ |
70 | - define('LOGBACKEND', 'filelog'); |
|
71 | - define('LOGLEVEL', LOGLEVEL_WBXML); |
|
72 | - define('LOGAUTHFAIL', false); |
|
73 | - |
|
74 | - // To save e.g. WBXML data only for selected users, add the usernames to the array |
|
75 | - // The data will be saved into a dedicated file per user in the LOGFILEDIR |
|
76 | - // Users have to be encapusulated in quotes, several users are comma separated, like: |
|
77 | - // $specialLogUsers = array('[email protected]', 'myusername'); |
|
78 | - define('LOGUSERLEVEL', LOGLEVEL_DEVICEID); |
|
79 | - $specialLogUsers = []; |
|
80 | - |
|
81 | - // Filelog settings |
|
82 | - define('LOGFILEDIR', '/var/log/grommunio-sync/'); |
|
83 | - define('LOGFILE', LOGFILEDIR . 'grommunio-sync.log'); |
|
84 | - define('LOGERRORFILE', LOGFILEDIR . 'grommunio-sync-error.log'); |
|
85 | - |
|
86 | - // Syslog settings |
|
87 | - // false will log to local syslog, otherwise put the remote syslog IP here |
|
88 | - define('LOG_SYSLOG_HOST', false); |
|
89 | - // Syslog port |
|
90 | - define('LOG_SYSLOG_PORT', 514); |
|
91 | - // Program showed in the syslog. Useful if you have more than one instance login to the same syslog |
|
92 | - define('LOG_SYSLOG_PROGRAM', 'grommunio-sync'); |
|
93 | - // Syslog facility - use LOG_USER when running on Windows |
|
94 | - define('LOG_SYSLOG_FACILITY', LOG_LOCAL0); |
|
95 | - |
|
96 | - // Location of the trusted CA, e.g. '/etc/ssl/certs/EmailCA.pem' |
|
97 | - // Uncomment and modify the following line if the validation of the certificates fails. |
|
98 | - // define('CAINFO', '/etc/ssl/certs/EmailCA.pem'); |
|
70 | + define('LOGBACKEND', 'filelog'); |
|
71 | + define('LOGLEVEL', LOGLEVEL_WBXML); |
|
72 | + define('LOGAUTHFAIL', false); |
|
73 | + |
|
74 | + // To save e.g. WBXML data only for selected users, add the usernames to the array |
|
75 | + // The data will be saved into a dedicated file per user in the LOGFILEDIR |
|
76 | + // Users have to be encapusulated in quotes, several users are comma separated, like: |
|
77 | + // $specialLogUsers = array('[email protected]', 'myusername'); |
|
78 | + define('LOGUSERLEVEL', LOGLEVEL_DEVICEID); |
|
79 | + $specialLogUsers = []; |
|
80 | + |
|
81 | + // Filelog settings |
|
82 | + define('LOGFILEDIR', '/var/log/grommunio-sync/'); |
|
83 | + define('LOGFILE', LOGFILEDIR . 'grommunio-sync.log'); |
|
84 | + define('LOGERRORFILE', LOGFILEDIR . 'grommunio-sync-error.log'); |
|
85 | + |
|
86 | + // Syslog settings |
|
87 | + // false will log to local syslog, otherwise put the remote syslog IP here |
|
88 | + define('LOG_SYSLOG_HOST', false); |
|
89 | + // Syslog port |
|
90 | + define('LOG_SYSLOG_PORT', 514); |
|
91 | + // Program showed in the syslog. Useful if you have more than one instance login to the same syslog |
|
92 | + define('LOG_SYSLOG_PROGRAM', 'grommunio-sync'); |
|
93 | + // Syslog facility - use LOG_USER when running on Windows |
|
94 | + define('LOG_SYSLOG_FACILITY', LOG_LOCAL0); |
|
95 | + |
|
96 | + // Location of the trusted CA, e.g. '/etc/ssl/certs/EmailCA.pem' |
|
97 | + // Uncomment and modify the following line if the validation of the certificates fails. |
|
98 | + // define('CAINFO', '/etc/ssl/certs/EmailCA.pem'); |
|
99 | 99 | |
100 | 100 | /* |
101 | 101 | * Mobile settings |
102 | 102 | */ |
103 | - // Device Provisioning |
|
104 | - define('PROVISIONING', true); |
|
105 | - |
|
106 | - // This option allows the 'loose enforcement' of the provisioning policies for older |
|
107 | - // devices which don't support provisioning (like WM 5 and HTC Android Mail) - dw2412 contribution |
|
108 | - // false (default) - Enforce provisioning for all devices |
|
109 | - // true - allow older devices, but enforce policies on devices which support it |
|
110 | - define('LOOSE_PROVISIONING', false); |
|
111 | - |
|
112 | - // Retrieve polcies for a user from admin API using the following endpoint |
|
113 | - define('ADMIN_API_POLICY_ENDPOINT', 'http://[::1]:8080/api/v1/service/syncPolicy/'); |
|
114 | - |
|
115 | - // Retrieve and update remote wipe status for a user and device from admin API using the following endpoint |
|
116 | - define('ADMIN_API_WIPE_ENDPOINT', 'http://[::1]:8080/api/v1/service/wipe/'); |
|
117 | - |
|
118 | - // Default conflict preference |
|
119 | - // Some devices allow to set if the server or PIM (mobile) |
|
120 | - // should win in case of a synchronization conflict |
|
121 | - // SYNC_CONFLICT_OVERWRITE_SERVER - Server is overwritten, PIM wins |
|
122 | - // SYNC_CONFLICT_OVERWRITE_PIM - PIM is overwritten, Server wins (default) |
|
123 | - define('SYNC_CONFLICT_DEFAULT', SYNC_CONFLICT_OVERWRITE_PIM); |
|
124 | - |
|
125 | - // Global limitation of items to be synchronized |
|
126 | - // The mobile can define a sync back period for calendar and email items |
|
127 | - // For large stores with many items the time period could be limited to a max value |
|
128 | - // If the mobile transmits a wider time period, the defined max value is used |
|
129 | - // Applicable values: |
|
130 | - // SYNC_FILTERTYPE_ALL (default, no limitation) |
|
131 | - // SYNC_FILTERTYPE_1DAY, SYNC_FILTERTYPE_3DAYS, SYNC_FILTERTYPE_1WEEK, SYNC_FILTERTYPE_2WEEKS, |
|
132 | - // SYNC_FILTERTYPE_1MONTH, SYNC_FILTERTYPE_3MONTHS, SYNC_FILTERTYPE_6MONTHS |
|
133 | - define('SYNC_FILTERTIME_MAX', SYNC_FILTERTYPE_ALL); |
|
134 | - |
|
135 | - // Interval in seconds before checking if there are changes on the server when in Ping. |
|
136 | - // It means the highest time span before a change is pushed to a mobile. Set it to |
|
137 | - // a higher value if you have a high load on the server. |
|
138 | - define('PING_INTERVAL', 30); |
|
139 | - |
|
140 | - // Set the fileas (save as) order for contacts in the webaccess/webapp/outlook. |
|
141 | - // It will only affect new/modified contacts on the mobile which then are synced to the server. |
|
142 | - // Possible values are: |
|
143 | - // SYNC_FILEAS_FIRSTLAST - fileas will be "Firstname Middlename Lastname" |
|
144 | - // SYNC_FILEAS_LASTFIRST - fileas will be "Lastname, Firstname Middlename" |
|
145 | - // SYNC_FILEAS_COMPANYONLY - fileas will be "Company" |
|
146 | - // SYNC_FILEAS_COMPANYLAST - fileas will be "Company (Lastname, Firstname Middlename)" |
|
147 | - // SYNC_FILEAS_COMPANYFIRST - fileas will be "Company (Firstname Middlename Lastname)" |
|
148 | - // SYNC_FILEAS_LASTCOMPANY - fileas will be "Lastname, Firstname Middlename (Company)" |
|
149 | - // SYNC_FILEAS_FIRSTCOMPANY - fileas will be "Firstname Middlename Lastname (Company)" |
|
150 | - // The company-fileas will only be set if a contact has a company set. If one of |
|
151 | - // company-fileas is selected and a contact doesn't have a company set, it will default |
|
152 | - // to SYNC_FILEAS_FIRSTLAST or SYNC_FILEAS_LASTFIRST (depending on if last or first |
|
153 | - // option is selected for company). |
|
154 | - // If SYNC_FILEAS_COMPANYONLY is selected and company of the contact is not set |
|
155 | - // SYNC_FILEAS_LASTFIRST will be used |
|
156 | - define('FILEAS_ORDER', SYNC_FILEAS_LASTFIRST); |
|
157 | - |
|
158 | - // Maximum amount of items to be synchronized per request. |
|
159 | - // Normally this value is requested by the mobile. Common values are 5, 25, 50 or 100. |
|
160 | - // Exporting too much items can cause mobile timeout on busy systems. |
|
161 | - // grommunio-sync will use the lowest provided value, either set here or by the mobile. |
|
162 | - // MS Outlook 2013+ request up to 512 items to accelerate the sync process. |
|
163 | - // If you detect high load (also on subsystems) you could try a lower setting. |
|
164 | - // max: 512 - value used if mobile does not limit amount of items |
|
165 | - define('SYNC_MAX_ITEMS', 512); |
|
166 | - |
|
167 | - // The devices usually send a list of supported properties for calendar and contact |
|
168 | - // items. If a device does not includes such a supported property in Sync request, |
|
169 | - // it means the property's value will be deleted on the server. |
|
170 | - // However some devices do not send a list of supported properties. It is then impossible |
|
171 | - // to tell if a property was deleted or it was not set at all if it does not appear in Sync. |
|
172 | - // This parameter defines grommunio-sync behaviour during Sync if a device does not issue a list with |
|
173 | - // supported properties. |
|
174 | - // See also https://jira.z-hub.io/browse/ZP-302. |
|
175 | - // Possible values: |
|
176 | - // false - do not unset properties which are not sent during Sync (default) |
|
177 | - // true - unset properties which are not sent during Sync |
|
178 | - define('UNSET_UNDEFINED_PROPERTIES', false); |
|
179 | - |
|
180 | - // ActiveSync specifies that a contact photo may not exceed 48 KB. This value is checked |
|
181 | - // in the semantic sanity checks and contacts with larger photos are not synchronized. |
|
182 | - // This limitation is not being followed by the ActiveSync clients which set much bigger |
|
183 | - // contact photos. You can override the default value of the max photo size. |
|
184 | - // default: 5242880 - 5 MB default max photo size in bytes |
|
185 | - define('SYNC_CONTACTS_MAXPICTURESIZE', 5242880); |
|
186 | - |
|
187 | - // Users with many folders can use the 'partial foldersync' feature, where the server |
|
188 | - // actively stops processing the folder list if it takes too long. Other requests are |
|
189 | - // then redirected to the FolderSync to synchronize the remaining items. |
|
190 | - // Device compatibility for this procedure is not fully understood. |
|
191 | - // NOTE: THIS IS AN EXPERIMENTAL FEATURE WHICH COULD PREVENT YOUR MOBILES FROM SYNCHRONIZING. |
|
192 | - define('USE_PARTIAL_FOLDERSYNC', false); |
|
193 | - |
|
194 | - // The minimum accepted time in second that a ping command should last. |
|
195 | - // It is strongly advised to keep this config to false. Some device |
|
196 | - // might not be able to send a higher value than the one specified here and thus |
|
197 | - // unable to start a push connection. |
|
198 | - // If set to false, there will be no lower bound to the ping lifetime. |
|
199 | - // The minimum accepted value is 1 second. The maximum accepted value is 3540 seconds (59 minutes). |
|
200 | - define('PING_LOWER_BOUND_LIFETIME', false); |
|
201 | - |
|
202 | - // The maximum accepted time in second that a ping command should last. |
|
203 | - // If set to false, there will be no higher bound to the ping lifetime. |
|
204 | - // The minimum accepted value is 1 second. The maximum accepted value is 3540 seconds (59 minutes). |
|
205 | - define('PING_HIGHER_BOUND_LIFETIME', false); |
|
206 | - |
|
207 | - // Maximum response time |
|
208 | - // Mobiles implement different timeouts to their TCP/IP connections. Android devices for example |
|
209 | - // have a hard timeout of 30 seconds. If the server is not able to answer a request within this timeframe, |
|
210 | - // the answer will not be received and the device will send a new one overloading the server. |
|
211 | - // There are three categories |
|
212 | - // - Short timeout - server has up within 30 seconds - is automatically applied for not categorized types |
|
213 | - // - Medium timeout - server has up to 90 seconds to respond |
|
214 | - // - Long timeout - server has up to 4 minutes to respond |
|
215 | - // If a timeout is almost reached the server will break and sent the results it has until this |
|
216 | - // point. You can add DeviceType strings to the categories. |
|
217 | - // In general longer timeouts are better, because more data can be streamed at once. |
|
218 | - define('SYNC_TIMEOUT_MEDIUM_DEVICETYPES', "SAMSUNGGTI"); |
|
219 | - define('SYNC_TIMEOUT_LONG_DEVICETYPES', "iPod, iPad, iPhone, WP, WindowsOutlook, WindowsMail"); |
|
220 | - |
|
221 | - // Time in seconds the device should wait whenever the service is unavailable, |
|
222 | - // e.g. when a backend service is unavailable. |
|
223 | - // grommunio-sync sends a "Retry-After" header in the response with the here defined value. |
|
224 | - // It is up to the device to respect or not this directive so even if this option is set, |
|
225 | - // the device might not wait requested time frame. |
|
226 | - // Number of seconds before retry, to disable set to: false |
|
227 | - define('RETRY_AFTER_DELAY', 300); |
|
103 | + // Device Provisioning |
|
104 | + define('PROVISIONING', true); |
|
105 | + |
|
106 | + // This option allows the 'loose enforcement' of the provisioning policies for older |
|
107 | + // devices which don't support provisioning (like WM 5 and HTC Android Mail) - dw2412 contribution |
|
108 | + // false (default) - Enforce provisioning for all devices |
|
109 | + // true - allow older devices, but enforce policies on devices which support it |
|
110 | + define('LOOSE_PROVISIONING', false); |
|
111 | + |
|
112 | + // Retrieve polcies for a user from admin API using the following endpoint |
|
113 | + define('ADMIN_API_POLICY_ENDPOINT', 'http://[::1]:8080/api/v1/service/syncPolicy/'); |
|
114 | + |
|
115 | + // Retrieve and update remote wipe status for a user and device from admin API using the following endpoint |
|
116 | + define('ADMIN_API_WIPE_ENDPOINT', 'http://[::1]:8080/api/v1/service/wipe/'); |
|
117 | + |
|
118 | + // Default conflict preference |
|
119 | + // Some devices allow to set if the server or PIM (mobile) |
|
120 | + // should win in case of a synchronization conflict |
|
121 | + // SYNC_CONFLICT_OVERWRITE_SERVER - Server is overwritten, PIM wins |
|
122 | + // SYNC_CONFLICT_OVERWRITE_PIM - PIM is overwritten, Server wins (default) |
|
123 | + define('SYNC_CONFLICT_DEFAULT', SYNC_CONFLICT_OVERWRITE_PIM); |
|
124 | + |
|
125 | + // Global limitation of items to be synchronized |
|
126 | + // The mobile can define a sync back period for calendar and email items |
|
127 | + // For large stores with many items the time period could be limited to a max value |
|
128 | + // If the mobile transmits a wider time period, the defined max value is used |
|
129 | + // Applicable values: |
|
130 | + // SYNC_FILTERTYPE_ALL (default, no limitation) |
|
131 | + // SYNC_FILTERTYPE_1DAY, SYNC_FILTERTYPE_3DAYS, SYNC_FILTERTYPE_1WEEK, SYNC_FILTERTYPE_2WEEKS, |
|
132 | + // SYNC_FILTERTYPE_1MONTH, SYNC_FILTERTYPE_3MONTHS, SYNC_FILTERTYPE_6MONTHS |
|
133 | + define('SYNC_FILTERTIME_MAX', SYNC_FILTERTYPE_ALL); |
|
134 | + |
|
135 | + // Interval in seconds before checking if there are changes on the server when in Ping. |
|
136 | + // It means the highest time span before a change is pushed to a mobile. Set it to |
|
137 | + // a higher value if you have a high load on the server. |
|
138 | + define('PING_INTERVAL', 30); |
|
139 | + |
|
140 | + // Set the fileas (save as) order for contacts in the webaccess/webapp/outlook. |
|
141 | + // It will only affect new/modified contacts on the mobile which then are synced to the server. |
|
142 | + // Possible values are: |
|
143 | + // SYNC_FILEAS_FIRSTLAST - fileas will be "Firstname Middlename Lastname" |
|
144 | + // SYNC_FILEAS_LASTFIRST - fileas will be "Lastname, Firstname Middlename" |
|
145 | + // SYNC_FILEAS_COMPANYONLY - fileas will be "Company" |
|
146 | + // SYNC_FILEAS_COMPANYLAST - fileas will be "Company (Lastname, Firstname Middlename)" |
|
147 | + // SYNC_FILEAS_COMPANYFIRST - fileas will be "Company (Firstname Middlename Lastname)" |
|
148 | + // SYNC_FILEAS_LASTCOMPANY - fileas will be "Lastname, Firstname Middlename (Company)" |
|
149 | + // SYNC_FILEAS_FIRSTCOMPANY - fileas will be "Firstname Middlename Lastname (Company)" |
|
150 | + // The company-fileas will only be set if a contact has a company set. If one of |
|
151 | + // company-fileas is selected and a contact doesn't have a company set, it will default |
|
152 | + // to SYNC_FILEAS_FIRSTLAST or SYNC_FILEAS_LASTFIRST (depending on if last or first |
|
153 | + // option is selected for company). |
|
154 | + // If SYNC_FILEAS_COMPANYONLY is selected and company of the contact is not set |
|
155 | + // SYNC_FILEAS_LASTFIRST will be used |
|
156 | + define('FILEAS_ORDER', SYNC_FILEAS_LASTFIRST); |
|
157 | + |
|
158 | + // Maximum amount of items to be synchronized per request. |
|
159 | + // Normally this value is requested by the mobile. Common values are 5, 25, 50 or 100. |
|
160 | + // Exporting too much items can cause mobile timeout on busy systems. |
|
161 | + // grommunio-sync will use the lowest provided value, either set here or by the mobile. |
|
162 | + // MS Outlook 2013+ request up to 512 items to accelerate the sync process. |
|
163 | + // If you detect high load (also on subsystems) you could try a lower setting. |
|
164 | + // max: 512 - value used if mobile does not limit amount of items |
|
165 | + define('SYNC_MAX_ITEMS', 512); |
|
166 | + |
|
167 | + // The devices usually send a list of supported properties for calendar and contact |
|
168 | + // items. If a device does not includes such a supported property in Sync request, |
|
169 | + // it means the property's value will be deleted on the server. |
|
170 | + // However some devices do not send a list of supported properties. It is then impossible |
|
171 | + // to tell if a property was deleted or it was not set at all if it does not appear in Sync. |
|
172 | + // This parameter defines grommunio-sync behaviour during Sync if a device does not issue a list with |
|
173 | + // supported properties. |
|
174 | + // See also https://jira.z-hub.io/browse/ZP-302. |
|
175 | + // Possible values: |
|
176 | + // false - do not unset properties which are not sent during Sync (default) |
|
177 | + // true - unset properties which are not sent during Sync |
|
178 | + define('UNSET_UNDEFINED_PROPERTIES', false); |
|
179 | + |
|
180 | + // ActiveSync specifies that a contact photo may not exceed 48 KB. This value is checked |
|
181 | + // in the semantic sanity checks and contacts with larger photos are not synchronized. |
|
182 | + // This limitation is not being followed by the ActiveSync clients which set much bigger |
|
183 | + // contact photos. You can override the default value of the max photo size. |
|
184 | + // default: 5242880 - 5 MB default max photo size in bytes |
|
185 | + define('SYNC_CONTACTS_MAXPICTURESIZE', 5242880); |
|
186 | + |
|
187 | + // Users with many folders can use the 'partial foldersync' feature, where the server |
|
188 | + // actively stops processing the folder list if it takes too long. Other requests are |
|
189 | + // then redirected to the FolderSync to synchronize the remaining items. |
|
190 | + // Device compatibility for this procedure is not fully understood. |
|
191 | + // NOTE: THIS IS AN EXPERIMENTAL FEATURE WHICH COULD PREVENT YOUR MOBILES FROM SYNCHRONIZING. |
|
192 | + define('USE_PARTIAL_FOLDERSYNC', false); |
|
193 | + |
|
194 | + // The minimum accepted time in second that a ping command should last. |
|
195 | + // It is strongly advised to keep this config to false. Some device |
|
196 | + // might not be able to send a higher value than the one specified here and thus |
|
197 | + // unable to start a push connection. |
|
198 | + // If set to false, there will be no lower bound to the ping lifetime. |
|
199 | + // The minimum accepted value is 1 second. The maximum accepted value is 3540 seconds (59 minutes). |
|
200 | + define('PING_LOWER_BOUND_LIFETIME', false); |
|
201 | + |
|
202 | + // The maximum accepted time in second that a ping command should last. |
|
203 | + // If set to false, there will be no higher bound to the ping lifetime. |
|
204 | + // The minimum accepted value is 1 second. The maximum accepted value is 3540 seconds (59 minutes). |
|
205 | + define('PING_HIGHER_BOUND_LIFETIME', false); |
|
206 | + |
|
207 | + // Maximum response time |
|
208 | + // Mobiles implement different timeouts to their TCP/IP connections. Android devices for example |
|
209 | + // have a hard timeout of 30 seconds. If the server is not able to answer a request within this timeframe, |
|
210 | + // the answer will not be received and the device will send a new one overloading the server. |
|
211 | + // There are three categories |
|
212 | + // - Short timeout - server has up within 30 seconds - is automatically applied for not categorized types |
|
213 | + // - Medium timeout - server has up to 90 seconds to respond |
|
214 | + // - Long timeout - server has up to 4 minutes to respond |
|
215 | + // If a timeout is almost reached the server will break and sent the results it has until this |
|
216 | + // point. You can add DeviceType strings to the categories. |
|
217 | + // In general longer timeouts are better, because more data can be streamed at once. |
|
218 | + define('SYNC_TIMEOUT_MEDIUM_DEVICETYPES', "SAMSUNGGTI"); |
|
219 | + define('SYNC_TIMEOUT_LONG_DEVICETYPES', "iPod, iPad, iPhone, WP, WindowsOutlook, WindowsMail"); |
|
220 | + |
|
221 | + // Time in seconds the device should wait whenever the service is unavailable, |
|
222 | + // e.g. when a backend service is unavailable. |
|
223 | + // grommunio-sync sends a "Retry-After" header in the response with the here defined value. |
|
224 | + // It is up to the device to respect or not this directive so even if this option is set, |
|
225 | + // the device might not wait requested time frame. |
|
226 | + // Number of seconds before retry, to disable set to: false |
|
227 | + define('RETRY_AFTER_DELAY', 300); |
|
228 | 228 | |
229 | 229 | /* |
230 | 230 | * Grommunio settings |
231 | 231 | */ |
232 | - // Defines the server to which we want to connect. |
|
233 | - define('MAPI_SERVER', 'default:'); |
|
232 | + // Defines the server to which we want to connect. |
|
233 | + define('MAPI_SERVER', 'default:'); |
|
234 | 234 | |
235 | - // Hidden state folder in store |
|
236 | - define('STORE_STATE_FOLDER', 'GS-SyncState'); |
|
235 | + // Hidden state folder in store |
|
236 | + define('STORE_STATE_FOLDER', 'GS-SyncState'); |
|
237 | 237 | |
238 | - // Redis host |
|
239 | - define('REDIS_HOST', 'localhost'); |
|
238 | + // Redis host |
|
239 | + define('REDIS_HOST', 'localhost'); |
|
240 | 240 | |
241 | - // Redis port |
|
242 | - define('REDIS_PORT', 6379); |
|
241 | + // Redis port |
|
242 | + define('REDIS_PORT', 6379); |
|
243 | 243 | |
244 | - // Redis authentication - leave empty to connect without authentication (default) |
|
245 | - define('REDIS_AUTH', ''); |
|
244 | + // Redis authentication - leave empty to connect without authentication (default) |
|
245 | + define('REDIS_AUTH', ''); |
|
246 | 246 | |
247 | - // Time in seconds for the server search. Setting it too high might result in timeout. |
|
248 | - // Setting it too low might not return all results. Default is 10. |
|
249 | - define('SEARCH_WAIT', 10); |
|
250 | - // The maximum number of results to send to the client. Setting it too high |
|
251 | - // might result in timeout. Default is 10. |
|
252 | - define('SEARCH_MAXRESULTS', 10); |
|
247 | + // Time in seconds for the server search. Setting it too high might result in timeout. |
|
248 | + // Setting it too low might not return all results. Default is 10. |
|
249 | + define('SEARCH_WAIT', 10); |
|
250 | + // The maximum number of results to send to the client. Setting it too high |
|
251 | + // might result in timeout. Default is 10. |
|
252 | + define('SEARCH_MAXRESULTS', 10); |
|
253 | 253 | |
254 | 254 | /* |
255 | 255 | * Synchronize additional folders to all mobiles |
@@ -294,10 +294,10 @@ discard block |
||
294 | 294 | * added/modified folders. |
295 | 295 | */ |
296 | 296 | |
297 | - $additionalFolders = [ |
|
298 | - // demo entry for the synchronization of contacts from the public folder. |
|
299 | - // uncomment (remove '/*' '*/') and fill in the folderid |
|
300 | - /* |
|
297 | + $additionalFolders = [ |
|
298 | + // demo entry for the synchronization of contacts from the public folder. |
|
299 | + // uncomment (remove '/*' '*/') and fill in the folderid |
|
300 | + /* |
|
301 | 301 | [ |
302 | 302 | 'store' => "SYSTEM", |
303 | 303 | 'folderid' => "", |
@@ -306,4 +306,4 @@ discard block |
||
306 | 306 | 'flags' => DeviceManager::FLD_FLAGS_NONE, |
307 | 307 | ], |
308 | 308 | */ |
309 | - ]; |
|
309 | + ]; |
@@ -14,7 +14,7 @@ discard block |
||
14 | 14 | define('TIMEZONE', ''); |
15 | 15 | |
16 | 16 | // Defines the base path on the server |
17 | - define('BASE_PATH', dirname($_SERVER['SCRIPT_FILENAME']) . '/'); |
|
17 | + define('BASE_PATH', dirname($_SERVER['SCRIPT_FILENAME']).'/'); |
|
18 | 18 | |
19 | 19 | // Try to set unlimited timeout |
20 | 20 | define('SCRIPT_TIMEOUT', 0); |
@@ -80,8 +80,8 @@ discard block |
||
80 | 80 | |
81 | 81 | // Filelog settings |
82 | 82 | define('LOGFILEDIR', '/var/log/grommunio-sync/'); |
83 | - define('LOGFILE', LOGFILEDIR . 'grommunio-sync.log'); |
|
84 | - define('LOGERRORFILE', LOGFILEDIR . 'grommunio-sync-error.log'); |
|
83 | + define('LOGFILE', LOGFILEDIR.'grommunio-sync.log'); |
|
84 | + define('LOGERRORFILE', LOGFILEDIR.'grommunio-sync-error.log'); |
|
85 | 85 | |
86 | 86 | // Syslog settings |
87 | 87 | // false will log to local syslog, otherwise put the remote syslog IP here |
@@ -15,250 +15,250 @@ |
||
15 | 15 | require_once 'vendor/autoload.php'; |
16 | 16 | |
17 | 17 | if (!defined('GSYNC_CONFIG')) { |
18 | - define('GSYNC_CONFIG', 'config.php'); |
|
18 | + define('GSYNC_CONFIG', 'config.php'); |
|
19 | 19 | } |
20 | 20 | |
21 | 21 | include_once GSYNC_CONFIG; |
22 | 22 | |
23 | - // Attempt to set maximum execution time |
|
24 | - ini_set('max_execution_time', SCRIPT_TIMEOUT); |
|
25 | - set_time_limit(SCRIPT_TIMEOUT); |
|
26 | - |
|
27 | - try { |
|
28 | - // check config & initialize the basics |
|
29 | - GSync::CheckConfig(); |
|
30 | - Request::Initialize(); |
|
31 | - SLog::Initialize(); |
|
32 | - |
|
33 | - SLog::Write(LOGLEVEL_DEBUG, "-------- Start"); |
|
34 | - SLog::Write( |
|
35 | - LOGLEVEL_DEBUG, |
|
36 | - sprintf( |
|
37 | - "cmd='%s' devType='%s' devId='%s' getUser='%s' from='%s' version='%s' method='%s'", |
|
38 | - Request::GetCommand(), |
|
39 | - Request::GetDeviceType(), |
|
40 | - Request::GetDeviceID(), |
|
41 | - Request::GetGETUser(), |
|
42 | - Request::GetRemoteAddr(), |
|
43 | - @constant('GROMMUNIOSYNC_VERSION'), |
|
44 | - Request::GetMethod() |
|
45 | - ) |
|
46 | - ); |
|
47 | - |
|
48 | - // always request the authorization header |
|
49 | - if (!Request::HasAuthenticationInfo() || !Request::GetGETUser()) { |
|
50 | - throw new AuthenticationRequiredException("Access denied. Please send authorisation information"); |
|
51 | - } |
|
52 | - |
|
53 | - GSync::CheckAdvancedConfig(); |
|
54 | - |
|
55 | - // Process request headers and look for AS headers |
|
56 | - Request::ProcessHeaders(); |
|
57 | - |
|
58 | - // Stop here if this is an OPTIONS request |
|
59 | - if (Request::IsMethodOPTIONS()) { |
|
60 | - RequestProcessor::Authenticate(); |
|
61 | - |
|
62 | - throw new NoPostRequestException("Options request", NoPostRequestException::OPTIONS_REQUEST); |
|
63 | - } |
|
64 | - |
|
65 | - // Check required GET parameters |
|
66 | - if (Request::IsMethodPOST() && (Request::GetCommandCode() === false || !Request::GetDeviceID() || !Request::GetDeviceType())) { |
|
67 | - throw new FatalException("Requested the grommunio-sync URL without the required GET parameters"); |
|
68 | - } |
|
69 | - |
|
70 | - // Load the backend |
|
71 | - $backend = GSync::GetBackend(); |
|
72 | - |
|
73 | - // check the provisioning information |
|
74 | - if ( |
|
75 | - PROVISIONING === true && |
|
76 | - Request::IsMethodPOST() && |
|
77 | - GSync::CommandNeedsProvisioning(Request::GetCommandCode()) && |
|
78 | - ( |
|
79 | - (Request::WasPolicyKeySent() && Request::GetPolicyKey() == 0) || |
|
80 | - GSync::GetProvisioningManager()->ProvisioningRequired(Request::GetPolicyKey()) |
|
81 | - ) && ( |
|
82 | - LOOSE_PROVISIONING === false || |
|
83 | - (LOOSE_PROVISIONING === true && Request::WasPolicyKeySent()) |
|
84 | - )) { |
|
85 | - // TODO for AS 14 send a wbxml response |
|
86 | - throw new ProvisioningRequiredException(); |
|
87 | - } |
|
88 | - |
|
89 | - // most commands require an authenticated user |
|
90 | - if (GSync::CommandNeedsAuthentication(Request::GetCommandCode())) { |
|
91 | - RequestProcessor::Authenticate(); |
|
92 | - } |
|
93 | - |
|
94 | - // Do the actual processing of the request |
|
95 | - if (Request::IsMethodGET()) { |
|
96 | - throw new NoPostRequestException("This is the grommunio-sync location and can only be accessed by Microsoft ActiveSync-capable devices", NoPostRequestException::GET_REQUEST); |
|
97 | - } |
|
98 | - |
|
99 | - // Do the actual request |
|
100 | - header(GSync::GetServerHeader()); |
|
101 | - |
|
102 | - if (RequestProcessor::isUserAuthenticated()) { |
|
103 | - header("X-Grommunio-Sync-Version: " . @constant('GROMMUNIOSYNC_VERSION')); |
|
104 | - |
|
105 | - // announce the supported AS versions (if not already sent to device) |
|
106 | - if (GSync::GetDeviceManager()->AnnounceASVersion()) { |
|
107 | - $versions = GSync::GetSupportedProtocolVersions(true); |
|
108 | - SLog::Write(LOGLEVEL_INFO, sprintf("Announcing latest AS version to device: %s", $versions)); |
|
109 | - header("X-MS-RP: " . $versions); |
|
110 | - } |
|
111 | - } |
|
112 | - |
|
113 | - RequestProcessor::Initialize(); |
|
114 | - RequestProcessor::HandleRequest(); |
|
115 | - |
|
116 | - // eventually the RequestProcessor wants to send other headers to the mobile |
|
117 | - foreach (RequestProcessor::GetSpecialHeaders() as $header) { |
|
118 | - SLog::Write(LOGLEVEL_DEBUG, sprintf("Special header: %s", $header)); |
|
119 | - header($header); |
|
120 | - } |
|
121 | - |
|
122 | - // stream the data |
|
123 | - $len = ob_get_length(); |
|
124 | - $data = ob_get_contents(); |
|
125 | - ob_end_clean(); |
|
126 | - |
|
127 | - // log amount of data transferred |
|
128 | - // TODO check $len when streaming more data (e.g. Attachments), as the data will be send chunked |
|
129 | - if (GSync::GetDeviceManager(false)) { |
|
130 | - GSync::GetDeviceManager()->SentData($len); |
|
131 | - } |
|
132 | - |
|
133 | - // Unfortunately, even though grommunio-sync can stream the data to the client |
|
134 | - // with a chunked encoding, using chunked encoding breaks the progress bar |
|
135 | - // on the PDA. So the data is de-chunk here, written a content-length header and |
|
136 | - // data send as a 'normal' packet. If the output packet exceeds 1MB (see ob_start) |
|
137 | - // then it will be sent as a chunked packet anyway because PHP will have to flush |
|
138 | - // the buffer. |
|
139 | - if (!headers_sent()) { |
|
140 | - header("Content-Length: {$len}"); |
|
141 | - } |
|
142 | - |
|
143 | - // send vnd.ms-sync.wbxml content type header if there is no content |
|
144 | - // otherwise text/html content type is added which might break some devices |
|
145 | - if (!headers_sent() && $len == 0) { |
|
146 | - header("Content-Type: application/vnd.ms-sync.wbxml"); |
|
147 | - } |
|
148 | - |
|
149 | - echo $data; |
|
150 | - |
|
151 | - // destruct backend after all data is on the stream |
|
152 | - $backend->Logoff(); |
|
153 | - } |
|
154 | - catch (NoPostRequestException $nopostex) { |
|
155 | - if ($nopostex->getCode() == NoPostRequestException::OPTIONS_REQUEST) { |
|
156 | - header(GSync::GetServerHeader()); |
|
157 | - header(GSync::GetSupportedProtocolVersions()); |
|
158 | - header(GSync::GetSupportedCommands()); |
|
159 | - SLog::Write(LOGLEVEL_INFO, $nopostex->getMessage()); |
|
160 | - } |
|
161 | - elseif ($nopostex->getCode() == NoPostRequestException::GET_REQUEST) { |
|
162 | - if (Request::GetUserAgent()) { |
|
163 | - SLog::Write(LOGLEVEL_INFO, sprintf("User-agent: '%s'", Request::GetUserAgent())); |
|
164 | - } |
|
165 | - if (!headers_sent() && $nopostex->showLegalNotice()) { |
|
166 | - GSync::PrintGrommunioSyncLegal('GET not supported', $nopostex->getMessage()); |
|
167 | - } |
|
168 | - } |
|
169 | - } |
|
170 | - catch (Exception $ex) { |
|
171 | - // Extract any previous exception message for logging purpose. |
|
172 | - $exclass = get_class($ex); |
|
173 | - $exception_message = $ex->getMessage(); |
|
174 | - if ($ex->getPrevious()) { |
|
175 | - do { |
|
176 | - $current_exception = $ex->getPrevious(); |
|
177 | - $exception_message .= ' -> ' . $current_exception->getMessage(); |
|
178 | - } |
|
179 | - while ($current_exception->getPrevious()); |
|
180 | - } |
|
181 | - |
|
182 | - if (Request::GetUserAgent()) { |
|
183 | - SLog::Write(LOGLEVEL_INFO, sprintf("User-agent: '%s'", Request::GetUserAgent())); |
|
184 | - } |
|
185 | - |
|
186 | - SLog::Write(LOGLEVEL_FATAL, sprintf('Exception: (%s) - %s', $exclass, $exception_message)); |
|
187 | - |
|
188 | - if (!headers_sent()) { |
|
189 | - if ($ex instanceof GSyncException) { |
|
190 | - header('HTTP/1.1 ' . $ex->getHTTPCodeString()); |
|
191 | - foreach ($ex->getHTTPHeaders() as $h) { |
|
192 | - header($h); |
|
193 | - } |
|
194 | - } |
|
195 | - // something really unexpected happened! |
|
196 | - else { |
|
197 | - header('HTTP/1.1 500 Internal Server Error'); |
|
198 | - } |
|
199 | - } |
|
200 | - |
|
201 | - if ($ex instanceof AuthenticationRequiredException) { |
|
202 | - // Only print GSync legal message for GET requests because |
|
203 | - // some devices send unauthorized OPTIONS requests |
|
204 | - // and don't expect anything in the response body |
|
205 | - if (Request::IsMethodGET()) { |
|
206 | - GSync::PrintGrommunioSyncLegal($exclass, sprintf('<pre>%s</pre>', $ex->getMessage())); |
|
207 | - } |
|
208 | - |
|
209 | - // log the failed login attempt e.g. for fail2ban |
|
210 | - if (defined('LOGAUTHFAIL') && LOGAUTHFAIL != false) { |
|
211 | - SLog::Write(LOGLEVEL_WARN, sprintf("IP: %s failed to authenticate user '%s'", Request::GetRemoteAddr(), Request::GetAuthUser() ? Request::GetAuthUser() : Request::GetGETUser())); |
|
212 | - } |
|
213 | - } |
|
214 | - |
|
215 | - // This could be a WBXML problem.. try to get the complete request |
|
216 | - elseif ($ex instanceof WBXMLException) { |
|
217 | - SLog::Write(LOGLEVEL_FATAL, "Request could not be processed correctly due to a WBXMLException. Please report this including the 'WBXML debug data' logged. Be aware that the debug data could contain confidential information."); |
|
218 | - } |
|
219 | - |
|
220 | - // Try to output some kind of error information. This is only possible if |
|
221 | - // the output had not started yet. If it has started already, we can't show the user the error, and |
|
222 | - // the device will give its own (useless) error message. |
|
223 | - elseif (!($ex instanceof GSyncException) || $ex->showLegalNotice()) { |
|
224 | - $cmdinfo = (Request::GetCommand()) ? sprintf(" processing command <i>%s</i>", Request::GetCommand()) : ""; |
|
225 | - $extrace = $ex->getTrace(); |
|
226 | - $trace = (!empty($extrace)) ? "\n\nTrace:\n" . print_r($extrace, 1) : ""; |
|
227 | - GSync::PrintGrommunioSyncLegal($exclass . $cmdinfo, sprintf('<pre>%s</pre>', $ex->getMessage() . $trace)); |
|
228 | - } |
|
229 | - |
|
230 | - // Announce exception to process loop detection |
|
231 | - if (GSync::GetDeviceManager(false)) { |
|
232 | - GSync::GetDeviceManager()->AnnounceProcessException($ex); |
|
233 | - } |
|
234 | - |
|
235 | - // Announce exception if the TopCollector if available |
|
236 | - GSync::GetTopCollector()->AnnounceInformation(get_class($ex), true); |
|
237 | - } |
|
238 | - |
|
239 | - // save device data if the DeviceManager is available |
|
240 | - if (GSync::GetDeviceManager(false)) { |
|
241 | - GSync::GetDeviceManager()->Save(); |
|
242 | - } |
|
243 | - |
|
244 | - // end gracefully |
|
245 | - SLog::Write( |
|
246 | - LOGLEVEL_INFO, |
|
247 | - sprintf( |
|
248 | - "cmd='%s' memory='%s/%s' time='%ss' devType='%s' devId='%s' getUser='%s' from='%s' idle='%ss' version='%s' method='%s' httpcode='%s'", |
|
249 | - Request::GetCommand(), |
|
250 | - Utils::FormatBytes(memory_get_peak_usage(false)), |
|
251 | - Utils::FormatBytes(memory_get_peak_usage(true)), |
|
252 | - number_format(microtime(true) - $_SERVER["REQUEST_TIME_FLOAT"], 2), |
|
253 | - Request::GetDeviceType(), |
|
254 | - Request::GetDeviceID(), |
|
255 | - Request::GetGETUser(), |
|
256 | - Request::GetRemoteAddr(), |
|
257 | - RequestProcessor::GetWaitTime(), |
|
258 | - @constant('GROMMUNIOSYNC_VERSION'), |
|
259 | - Request::GetMethod(), |
|
260 | - http_response_code() |
|
261 | - ) |
|
262 | - ); |
|
263 | - |
|
264 | - SLog::Write(LOGLEVEL_DEBUG, "-------- End"); |
|
23 | + // Attempt to set maximum execution time |
|
24 | + ini_set('max_execution_time', SCRIPT_TIMEOUT); |
|
25 | + set_time_limit(SCRIPT_TIMEOUT); |
|
26 | + |
|
27 | + try { |
|
28 | + // check config & initialize the basics |
|
29 | + GSync::CheckConfig(); |
|
30 | + Request::Initialize(); |
|
31 | + SLog::Initialize(); |
|
32 | + |
|
33 | + SLog::Write(LOGLEVEL_DEBUG, "-------- Start"); |
|
34 | + SLog::Write( |
|
35 | + LOGLEVEL_DEBUG, |
|
36 | + sprintf( |
|
37 | + "cmd='%s' devType='%s' devId='%s' getUser='%s' from='%s' version='%s' method='%s'", |
|
38 | + Request::GetCommand(), |
|
39 | + Request::GetDeviceType(), |
|
40 | + Request::GetDeviceID(), |
|
41 | + Request::GetGETUser(), |
|
42 | + Request::GetRemoteAddr(), |
|
43 | + @constant('GROMMUNIOSYNC_VERSION'), |
|
44 | + Request::GetMethod() |
|
45 | + ) |
|
46 | + ); |
|
47 | + |
|
48 | + // always request the authorization header |
|
49 | + if (!Request::HasAuthenticationInfo() || !Request::GetGETUser()) { |
|
50 | + throw new AuthenticationRequiredException("Access denied. Please send authorisation information"); |
|
51 | + } |
|
52 | + |
|
53 | + GSync::CheckAdvancedConfig(); |
|
54 | + |
|
55 | + // Process request headers and look for AS headers |
|
56 | + Request::ProcessHeaders(); |
|
57 | + |
|
58 | + // Stop here if this is an OPTIONS request |
|
59 | + if (Request::IsMethodOPTIONS()) { |
|
60 | + RequestProcessor::Authenticate(); |
|
61 | + |
|
62 | + throw new NoPostRequestException("Options request", NoPostRequestException::OPTIONS_REQUEST); |
|
63 | + } |
|
64 | + |
|
65 | + // Check required GET parameters |
|
66 | + if (Request::IsMethodPOST() && (Request::GetCommandCode() === false || !Request::GetDeviceID() || !Request::GetDeviceType())) { |
|
67 | + throw new FatalException("Requested the grommunio-sync URL without the required GET parameters"); |
|
68 | + } |
|
69 | + |
|
70 | + // Load the backend |
|
71 | + $backend = GSync::GetBackend(); |
|
72 | + |
|
73 | + // check the provisioning information |
|
74 | + if ( |
|
75 | + PROVISIONING === true && |
|
76 | + Request::IsMethodPOST() && |
|
77 | + GSync::CommandNeedsProvisioning(Request::GetCommandCode()) && |
|
78 | + ( |
|
79 | + (Request::WasPolicyKeySent() && Request::GetPolicyKey() == 0) || |
|
80 | + GSync::GetProvisioningManager()->ProvisioningRequired(Request::GetPolicyKey()) |
|
81 | + ) && ( |
|
82 | + LOOSE_PROVISIONING === false || |
|
83 | + (LOOSE_PROVISIONING === true && Request::WasPolicyKeySent()) |
|
84 | + )) { |
|
85 | + // TODO for AS 14 send a wbxml response |
|
86 | + throw new ProvisioningRequiredException(); |
|
87 | + } |
|
88 | + |
|
89 | + // most commands require an authenticated user |
|
90 | + if (GSync::CommandNeedsAuthentication(Request::GetCommandCode())) { |
|
91 | + RequestProcessor::Authenticate(); |
|
92 | + } |
|
93 | + |
|
94 | + // Do the actual processing of the request |
|
95 | + if (Request::IsMethodGET()) { |
|
96 | + throw new NoPostRequestException("This is the grommunio-sync location and can only be accessed by Microsoft ActiveSync-capable devices", NoPostRequestException::GET_REQUEST); |
|
97 | + } |
|
98 | + |
|
99 | + // Do the actual request |
|
100 | + header(GSync::GetServerHeader()); |
|
101 | + |
|
102 | + if (RequestProcessor::isUserAuthenticated()) { |
|
103 | + header("X-Grommunio-Sync-Version: " . @constant('GROMMUNIOSYNC_VERSION')); |
|
104 | + |
|
105 | + // announce the supported AS versions (if not already sent to device) |
|
106 | + if (GSync::GetDeviceManager()->AnnounceASVersion()) { |
|
107 | + $versions = GSync::GetSupportedProtocolVersions(true); |
|
108 | + SLog::Write(LOGLEVEL_INFO, sprintf("Announcing latest AS version to device: %s", $versions)); |
|
109 | + header("X-MS-RP: " . $versions); |
|
110 | + } |
|
111 | + } |
|
112 | + |
|
113 | + RequestProcessor::Initialize(); |
|
114 | + RequestProcessor::HandleRequest(); |
|
115 | + |
|
116 | + // eventually the RequestProcessor wants to send other headers to the mobile |
|
117 | + foreach (RequestProcessor::GetSpecialHeaders() as $header) { |
|
118 | + SLog::Write(LOGLEVEL_DEBUG, sprintf("Special header: %s", $header)); |
|
119 | + header($header); |
|
120 | + } |
|
121 | + |
|
122 | + // stream the data |
|
123 | + $len = ob_get_length(); |
|
124 | + $data = ob_get_contents(); |
|
125 | + ob_end_clean(); |
|
126 | + |
|
127 | + // log amount of data transferred |
|
128 | + // TODO check $len when streaming more data (e.g. Attachments), as the data will be send chunked |
|
129 | + if (GSync::GetDeviceManager(false)) { |
|
130 | + GSync::GetDeviceManager()->SentData($len); |
|
131 | + } |
|
132 | + |
|
133 | + // Unfortunately, even though grommunio-sync can stream the data to the client |
|
134 | + // with a chunked encoding, using chunked encoding breaks the progress bar |
|
135 | + // on the PDA. So the data is de-chunk here, written a content-length header and |
|
136 | + // data send as a 'normal' packet. If the output packet exceeds 1MB (see ob_start) |
|
137 | + // then it will be sent as a chunked packet anyway because PHP will have to flush |
|
138 | + // the buffer. |
|
139 | + if (!headers_sent()) { |
|
140 | + header("Content-Length: {$len}"); |
|
141 | + } |
|
142 | + |
|
143 | + // send vnd.ms-sync.wbxml content type header if there is no content |
|
144 | + // otherwise text/html content type is added which might break some devices |
|
145 | + if (!headers_sent() && $len == 0) { |
|
146 | + header("Content-Type: application/vnd.ms-sync.wbxml"); |
|
147 | + } |
|
148 | + |
|
149 | + echo $data; |
|
150 | + |
|
151 | + // destruct backend after all data is on the stream |
|
152 | + $backend->Logoff(); |
|
153 | + } |
|
154 | + catch (NoPostRequestException $nopostex) { |
|
155 | + if ($nopostex->getCode() == NoPostRequestException::OPTIONS_REQUEST) { |
|
156 | + header(GSync::GetServerHeader()); |
|
157 | + header(GSync::GetSupportedProtocolVersions()); |
|
158 | + header(GSync::GetSupportedCommands()); |
|
159 | + SLog::Write(LOGLEVEL_INFO, $nopostex->getMessage()); |
|
160 | + } |
|
161 | + elseif ($nopostex->getCode() == NoPostRequestException::GET_REQUEST) { |
|
162 | + if (Request::GetUserAgent()) { |
|
163 | + SLog::Write(LOGLEVEL_INFO, sprintf("User-agent: '%s'", Request::GetUserAgent())); |
|
164 | + } |
|
165 | + if (!headers_sent() && $nopostex->showLegalNotice()) { |
|
166 | + GSync::PrintGrommunioSyncLegal('GET not supported', $nopostex->getMessage()); |
|
167 | + } |
|
168 | + } |
|
169 | + } |
|
170 | + catch (Exception $ex) { |
|
171 | + // Extract any previous exception message for logging purpose. |
|
172 | + $exclass = get_class($ex); |
|
173 | + $exception_message = $ex->getMessage(); |
|
174 | + if ($ex->getPrevious()) { |
|
175 | + do { |
|
176 | + $current_exception = $ex->getPrevious(); |
|
177 | + $exception_message .= ' -> ' . $current_exception->getMessage(); |
|
178 | + } |
|
179 | + while ($current_exception->getPrevious()); |
|
180 | + } |
|
181 | + |
|
182 | + if (Request::GetUserAgent()) { |
|
183 | + SLog::Write(LOGLEVEL_INFO, sprintf("User-agent: '%s'", Request::GetUserAgent())); |
|
184 | + } |
|
185 | + |
|
186 | + SLog::Write(LOGLEVEL_FATAL, sprintf('Exception: (%s) - %s', $exclass, $exception_message)); |
|
187 | + |
|
188 | + if (!headers_sent()) { |
|
189 | + if ($ex instanceof GSyncException) { |
|
190 | + header('HTTP/1.1 ' . $ex->getHTTPCodeString()); |
|
191 | + foreach ($ex->getHTTPHeaders() as $h) { |
|
192 | + header($h); |
|
193 | + } |
|
194 | + } |
|
195 | + // something really unexpected happened! |
|
196 | + else { |
|
197 | + header('HTTP/1.1 500 Internal Server Error'); |
|
198 | + } |
|
199 | + } |
|
200 | + |
|
201 | + if ($ex instanceof AuthenticationRequiredException) { |
|
202 | + // Only print GSync legal message for GET requests because |
|
203 | + // some devices send unauthorized OPTIONS requests |
|
204 | + // and don't expect anything in the response body |
|
205 | + if (Request::IsMethodGET()) { |
|
206 | + GSync::PrintGrommunioSyncLegal($exclass, sprintf('<pre>%s</pre>', $ex->getMessage())); |
|
207 | + } |
|
208 | + |
|
209 | + // log the failed login attempt e.g. for fail2ban |
|
210 | + if (defined('LOGAUTHFAIL') && LOGAUTHFAIL != false) { |
|
211 | + SLog::Write(LOGLEVEL_WARN, sprintf("IP: %s failed to authenticate user '%s'", Request::GetRemoteAddr(), Request::GetAuthUser() ? Request::GetAuthUser() : Request::GetGETUser())); |
|
212 | + } |
|
213 | + } |
|
214 | + |
|
215 | + // This could be a WBXML problem.. try to get the complete request |
|
216 | + elseif ($ex instanceof WBXMLException) { |
|
217 | + SLog::Write(LOGLEVEL_FATAL, "Request could not be processed correctly due to a WBXMLException. Please report this including the 'WBXML debug data' logged. Be aware that the debug data could contain confidential information."); |
|
218 | + } |
|
219 | + |
|
220 | + // Try to output some kind of error information. This is only possible if |
|
221 | + // the output had not started yet. If it has started already, we can't show the user the error, and |
|
222 | + // the device will give its own (useless) error message. |
|
223 | + elseif (!($ex instanceof GSyncException) || $ex->showLegalNotice()) { |
|
224 | + $cmdinfo = (Request::GetCommand()) ? sprintf(" processing command <i>%s</i>", Request::GetCommand()) : ""; |
|
225 | + $extrace = $ex->getTrace(); |
|
226 | + $trace = (!empty($extrace)) ? "\n\nTrace:\n" . print_r($extrace, 1) : ""; |
|
227 | + GSync::PrintGrommunioSyncLegal($exclass . $cmdinfo, sprintf('<pre>%s</pre>', $ex->getMessage() . $trace)); |
|
228 | + } |
|
229 | + |
|
230 | + // Announce exception to process loop detection |
|
231 | + if (GSync::GetDeviceManager(false)) { |
|
232 | + GSync::GetDeviceManager()->AnnounceProcessException($ex); |
|
233 | + } |
|
234 | + |
|
235 | + // Announce exception if the TopCollector if available |
|
236 | + GSync::GetTopCollector()->AnnounceInformation(get_class($ex), true); |
|
237 | + } |
|
238 | + |
|
239 | + // save device data if the DeviceManager is available |
|
240 | + if (GSync::GetDeviceManager(false)) { |
|
241 | + GSync::GetDeviceManager()->Save(); |
|
242 | + } |
|
243 | + |
|
244 | + // end gracefully |
|
245 | + SLog::Write( |
|
246 | + LOGLEVEL_INFO, |
|
247 | + sprintf( |
|
248 | + "cmd='%s' memory='%s/%s' time='%ss' devType='%s' devId='%s' getUser='%s' from='%s' idle='%ss' version='%s' method='%s' httpcode='%s'", |
|
249 | + Request::GetCommand(), |
|
250 | + Utils::FormatBytes(memory_get_peak_usage(false)), |
|
251 | + Utils::FormatBytes(memory_get_peak_usage(true)), |
|
252 | + number_format(microtime(true) - $_SERVER["REQUEST_TIME_FLOAT"], 2), |
|
253 | + Request::GetDeviceType(), |
|
254 | + Request::GetDeviceID(), |
|
255 | + Request::GetGETUser(), |
|
256 | + Request::GetRemoteAddr(), |
|
257 | + RequestProcessor::GetWaitTime(), |
|
258 | + @constant('GROMMUNIOSYNC_VERSION'), |
|
259 | + Request::GetMethod(), |
|
260 | + http_response_code() |
|
261 | + ) |
|
262 | + ); |
|
263 | + |
|
264 | + SLog::Write(LOGLEVEL_DEBUG, "-------- End"); |
@@ -100,13 +100,13 @@ discard block |
||
100 | 100 | header(GSync::GetServerHeader()); |
101 | 101 | |
102 | 102 | if (RequestProcessor::isUserAuthenticated()) { |
103 | - header("X-Grommunio-Sync-Version: " . @constant('GROMMUNIOSYNC_VERSION')); |
|
103 | + header("X-Grommunio-Sync-Version: ".@constant('GROMMUNIOSYNC_VERSION')); |
|
104 | 104 | |
105 | 105 | // announce the supported AS versions (if not already sent to device) |
106 | 106 | if (GSync::GetDeviceManager()->AnnounceASVersion()) { |
107 | 107 | $versions = GSync::GetSupportedProtocolVersions(true); |
108 | 108 | SLog::Write(LOGLEVEL_INFO, sprintf("Announcing latest AS version to device: %s", $versions)); |
109 | - header("X-MS-RP: " . $versions); |
|
109 | + header("X-MS-RP: ".$versions); |
|
110 | 110 | } |
111 | 111 | } |
112 | 112 | |
@@ -174,7 +174,7 @@ discard block |
||
174 | 174 | if ($ex->getPrevious()) { |
175 | 175 | do { |
176 | 176 | $current_exception = $ex->getPrevious(); |
177 | - $exception_message .= ' -> ' . $current_exception->getMessage(); |
|
177 | + $exception_message .= ' -> '.$current_exception->getMessage(); |
|
178 | 178 | } |
179 | 179 | while ($current_exception->getPrevious()); |
180 | 180 | } |
@@ -187,7 +187,7 @@ discard block |
||
187 | 187 | |
188 | 188 | if (!headers_sent()) { |
189 | 189 | if ($ex instanceof GSyncException) { |
190 | - header('HTTP/1.1 ' . $ex->getHTTPCodeString()); |
|
190 | + header('HTTP/1.1 '.$ex->getHTTPCodeString()); |
|
191 | 191 | foreach ($ex->getHTTPHeaders() as $h) { |
192 | 192 | header($h); |
193 | 193 | } |
@@ -223,8 +223,8 @@ discard block |
||
223 | 223 | elseif (!($ex instanceof GSyncException) || $ex->showLegalNotice()) { |
224 | 224 | $cmdinfo = (Request::GetCommand()) ? sprintf(" processing command <i>%s</i>", Request::GetCommand()) : ""; |
225 | 225 | $extrace = $ex->getTrace(); |
226 | - $trace = (!empty($extrace)) ? "\n\nTrace:\n" . print_r($extrace, 1) : ""; |
|
227 | - GSync::PrintGrommunioSyncLegal($exclass . $cmdinfo, sprintf('<pre>%s</pre>', $ex->getMessage() . $trace)); |
|
226 | + $trace = (!empty($extrace)) ? "\n\nTrace:\n".print_r($extrace, 1) : ""; |
|
227 | + GSync::PrintGrommunioSyncLegal($exclass.$cmdinfo, sprintf('<pre>%s</pre>', $ex->getMessage().$trace)); |
|
228 | 228 | } |
229 | 229 | |
230 | 230 | // Announce exception to process loop detection |
@@ -150,15 +150,13 @@ discard block |
||
150 | 150 | |
151 | 151 | // destruct backend after all data is on the stream |
152 | 152 | $backend->Logoff(); |
153 | - } |
|
154 | - catch (NoPostRequestException $nopostex) { |
|
153 | + } catch (NoPostRequestException $nopostex) { |
|
155 | 154 | if ($nopostex->getCode() == NoPostRequestException::OPTIONS_REQUEST) { |
156 | 155 | header(GSync::GetServerHeader()); |
157 | 156 | header(GSync::GetSupportedProtocolVersions()); |
158 | 157 | header(GSync::GetSupportedCommands()); |
159 | 158 | SLog::Write(LOGLEVEL_INFO, $nopostex->getMessage()); |
160 | - } |
|
161 | - elseif ($nopostex->getCode() == NoPostRequestException::GET_REQUEST) { |
|
159 | + } elseif ($nopostex->getCode() == NoPostRequestException::GET_REQUEST) { |
|
162 | 160 | if (Request::GetUserAgent()) { |
163 | 161 | SLog::Write(LOGLEVEL_INFO, sprintf("User-agent: '%s'", Request::GetUserAgent())); |
164 | 162 | } |
@@ -166,8 +164,7 @@ discard block |
||
166 | 164 | GSync::PrintGrommunioSyncLegal('GET not supported', $nopostex->getMessage()); |
167 | 165 | } |
168 | 166 | } |
169 | - } |
|
170 | - catch (Exception $ex) { |
|
167 | + } catch (Exception $ex) { |
|
171 | 168 | // Extract any previous exception message for logging purpose. |
172 | 169 | $exclass = get_class($ex); |
173 | 170 | $exception_message = $ex->getMessage(); |