Passed
Push — master ( fb9929...896406 )
by
unknown
30:22 queued 18:46
created

class.meetingrequest.php (425 issues)

1
<?php
2
/*
3
 * SPDX-License-Identifier: AGPL-3.0-only
4
 * SPDX-FileCopyrightText: Copyright 2005-2016 Zarafa Deutschland GmbH
5
 * SPDX-FileCopyrightText: Copyright 2020-2022 grommunio GmbH
6
 */
7
8
class Meetingrequest {
9
	/*
10
	 * NOTE
11
	 *
12
	 * This class is designed to modify and update meeting request properties
13
	 * and to search for linked appointments in the calendar. It does not
14
	 * - set standard properties like subject or location
15
	 * - commit property changes through savechanges() (except in accept() and decline())
16
	 *
17
	 * To set all the other properties, just handle the item as any other appointment
18
	 * item. You aren't even required to set those properties before or after using
19
	 * this class. If you update properties before REsending a meeting request (ie with
20
	 * a time change) you MUST first call updateMeetingRequest() so the internal counters
21
	 * can be updated. You can then submit the message any way you like.
22
	 *
23
	 */
24
25
	/*
26
	 * How to use
27
	 * ----------
28
	 *
29
	 * Sending a meeting request:
30
	 * - Create appointment item as normal, but as 'tentative'
31
	 *   (this is the state of the item when the receiving user has received but
32
	 *    not accepted the item)
33
	 * - Set recipients as normally in e-mails
34
	 * - Create Meetingrequest class instance
35
	 * - Call checkCalendarWriteAccess(), to check for write permissions on calendar folder
36
	 * - Call setMeetingRequest(), this turns on all the meeting request properties in the
37
	 *   calendar item
38
	 * - Call sendMeetingRequest(), this sends a copy of the item with some extra properties
39
	 *
40
	 * Updating a meeting request:
41
	 * - Create Meetingrequest class instance
42
	 * - Call checkCalendarWriteAccess(), to check for write permissions on calendar folder
43
	 * - Call updateMeetingRequest(), this updates the counters
44
	 * - Call checkSignificantChanges(), this will check for significant changes and if needed will clear the
45
	 *   existing recipient responses
46
	 * - Call sendMeetingRequest()
47
	 *
48
	 * Clicking on a an e-mail:
49
	 * - Create Meetingrequest class instance
50
	 * - Check isMeetingRequest(), if true:
51
	 *   - Check isLocalOrganiser(), if true then ignore the message
52
	 *   - Check isInCalendar(), if not call doAccept(true, false, false). This adds the item in your
53
	 *     calendar as tentative without sending a response
54
	 *   - Show Accept, Tentative, Decline buttons
55
	 *   - When the user presses Accept, Tentative or Decline, call doAccept(false, true, true),
56
	 *     doAccept(true, true, true) or doDecline(true) respectively to really accept or decline and
57
	 *     send the response. This will remove the request from your inbox.
58
	 * - Check isMeetingRequestResponse, if true:
59
	 *   - Check isLocalOrganiser(), if not true then ignore the message
60
	 *   - Call processMeetingRequestResponse()
61
	 *     This will update the trackstatus of all recipients, and set the item to 'busy'
62
	 *     when all the recipients have accepted.
63
	 * - Check isMeetingCancellation(), if true:
64
	 *   - Check isLocalOrganiser(), if true then ignore the message
65
	 *   - Check isInCalendar(), if not, then ignore
66
	 *     Call processMeetingCancellation()
67
	 *   - Show 'Remove From Calendar' button to user
68
	 *   - When userpresses button, call doRemoveFromCalendar(), which removes the item from your
69
	 *     calendar and deletes the message
70
	 *
71
	 * Cancelling a meeting request:
72
	 *   - Call doCancelInvitation, which will send cancellation mails to attendees and will remove
73
	 *     meeting object from calendar
74
	 */
75
76
	// All properties for a recipient that are interesting
77
	public $recipprops = [
78
		PR_ENTRYID,
79
		PR_DISPLAY_NAME,
0 ignored issues
show
The constant PR_DISPLAY_NAME was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
80
		PR_EMAIL_ADDRESS,
0 ignored issues
show
The constant PR_EMAIL_ADDRESS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
81
		PR_RECIPIENT_ENTRYID,
0 ignored issues
show
The constant PR_RECIPIENT_ENTRYID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
82
		PR_RECIPIENT_TYPE,
0 ignored issues
show
The constant PR_RECIPIENT_TYPE was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
83
		PR_SEND_INTERNET_ENCODING,
0 ignored issues
show
The constant PR_SEND_INTERNET_ENCODING was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
84
		PR_SEND_RICH_INFO,
0 ignored issues
show
The constant PR_SEND_RICH_INFO was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
85
		PR_RECIPIENT_DISPLAY_NAME,
0 ignored issues
show
The constant PR_RECIPIENT_DISPLAY_NAME was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
86
		PR_ADDRTYPE,
0 ignored issues
show
The constant PR_ADDRTYPE was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
87
		PR_DISPLAY_TYPE,
0 ignored issues
show
The constant PR_DISPLAY_TYPE was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
88
		PR_DISPLAY_TYPE_EX,
0 ignored issues
show
The constant PR_DISPLAY_TYPE_EX was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
89
		PR_RECIPIENT_TRACKSTATUS,
0 ignored issues
show
The constant PR_RECIPIENT_TRACKSTATUS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
90
		PR_RECIPIENT_TRACKSTATUS_TIME,
0 ignored issues
show
The constant PR_RECIPIENT_TRACKSTATUS_TIME was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
91
		PR_RECIPIENT_FLAGS,
0 ignored issues
show
The constant PR_RECIPIENT_FLAGS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
92
		PR_ROWID,
0 ignored issues
show
The constant PR_ROWID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
93
		PR_OBJECT_TYPE,
0 ignored issues
show
The constant PR_OBJECT_TYPE was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
94
		PR_SEARCH_KEY,
0 ignored issues
show
The constant PR_SEARCH_KEY was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
95
	];
96
97
	/**
98
	 * Indication whether the setting of resources in a Meeting Request is success (false) or if it
99
	 * has failed (integer).
100
	 *
101
	 * @var null|false|int
102
	 *
103
	 * @psalm-var 1|3|4|false|null
104
	 */
105
	public $errorSetResource;
106
107
	public $proptags;
108
	private $store;
109
	public $message;
110
	private $session;
111
112
	/**
113
	 * @var false|string
114
	 */
115
	private $meetingTimeInfo;
116
	private $enableDirectBooking;
117
118
	/**
119
	 * @var null|bool
120
	 */
121
	private $includesResources;
122
	private $nonAcceptingResources;
123
	private $recipientDisplayname;
124
125
	/**
126
	 * Constructor.
127
	 *
128
	 * Takes a store and a message. The message is an appointment item
129
	 * that should be converted into a meeting request or an incoming
130
	 * e-mail message that is a meeting request.
131
	 *
132
	 * The $session variable is optional, but required if the following features
133
	 * are to be used:
134
	 *
135
	 * - Sending meeting requests for meetings that are not in your own store
136
	 * - Sending meeting requests to resources, resource availability checking and resource freebusy updates
137
	 *
138
	 * @param mixed $store
139
	 * @param mixed $message
140
	 * @param mixed $session
141
	 * @param mixed $enableDirectBooking
142
	 */
143
	public function __construct($store, $message, $session = false, $enableDirectBooking = true) {
144
		$this->store = $store;
145
		$this->message = $message;
146
		$this->session = $session;
147
		// This variable string saves time information for the MR.
148
		$this->meetingTimeInfo = false;
149
		$this->enableDirectBooking = $enableDirectBooking;
150
151
		$properties = [];
152
		$properties['goid'] = 'PT_BINARY:PSETID_Meeting:0x3';
153
		$properties['goid2'] = 'PT_BINARY:PSETID_Meeting:0x23';
154
		$properties['type'] = 'PT_STRING8:PSETID_Meeting:0x24';
155
		$properties['meetingrecurring'] = 'PT_BOOLEAN:PSETID_Meeting:0x5';
156
		$properties['unknown2'] = 'PT_BOOLEAN:PSETID_Meeting:0xa';
157
		$properties['attendee_critical_change'] = 'PT_SYSTIME:PSETID_Meeting:0x1';
158
		$properties['owner_critical_change'] = 'PT_SYSTIME:PSETID_Meeting:0x1a';
159
		$properties['meetingstatus'] = 'PT_LONG:PSETID_Appointment:' . PidLidAppointmentStateFlags;
0 ignored issues
show
The constant PidLidAppointmentStateFlags was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
160
		$properties['responsestatus'] = 'PT_LONG:PSETID_Appointment:0x8218';
161
		$properties['unknown6'] = 'PT_LONG:PSETID_Meeting:0x4';
162
		$properties['replytime'] = 'PT_SYSTIME:PSETID_Appointment:0x8220';
163
		$properties['usetnef'] = 'PT_BOOLEAN:PSETID_Common:0x8582';
164
		$properties['recurrence_data'] = 'PT_BINARY:PSETID_Appointment:' . PidLidAppointmentRecur;
0 ignored issues
show
The constant PidLidAppointmentRecur was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
165
		$properties['reminderminutes'] = 'PT_LONG:PSETID_Common:' . PidLidReminderDelta;
0 ignored issues
show
The constant PidLidReminderDelta was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
166
		$properties['reminderset'] = 'PT_BOOLEAN:PSETID_Common:' . PidLidReminderSet;
0 ignored issues
show
The constant PidLidReminderSet was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
167
		$properties['sendasical'] = 'PT_BOOLEAN:PSETID_Appointment:0x8200';
168
		$properties['updatecounter'] = 'PT_LONG:PSETID_Appointment:' . PidLidAppointmentSequence;					// AppointmentSequenceNumber
0 ignored issues
show
The constant PidLidAppointmentSequence was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
169
		$properties['unknown7'] = 'PT_LONG:PSETID_Appointment:0x8202';
170
		$properties['last_updatecounter'] = 'PT_LONG:PSETID_Appointment:0x8203';			// AppointmentLastSequence
171
		$properties['busystatus'] = 'PT_LONG:PSETID_Appointment:' . PidLidBusyStatus;
0 ignored issues
show
The constant PidLidBusyStatus was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
172
		$properties['intendedbusystatus'] = 'PT_LONG:PSETID_Appointment:' . PidLidIntendedBusyStatus;
0 ignored issues
show
The constant PidLidIntendedBusyStatus was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
173
		$properties['start'] = 'PT_SYSTIME:PSETID_Appointment:' . PidLidAppointmentStartWhole;
0 ignored issues
show
The constant PidLidAppointmentStartWhole was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
174
		$properties['responselocation'] = 'PT_STRING8:PSETID_Meeting:0x2';
175
		$properties['location'] = 'PT_STRING8:PSETID_Appointment:' . PidLidLocation;
0 ignored issues
show
The constant PidLidLocation was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
176
		$properties['requestsent'] = 'PT_BOOLEAN:PSETID_Appointment:0x8229';		// PidLidFInvited, MeetingRequestWasSent
177
		$properties['startdate'] = 'PT_SYSTIME:PSETID_Appointment:' . PidLidAppointmentStartWhole;
178
		$properties['duedate'] = 'PT_SYSTIME:PSETID_Appointment:' . PidLidAppointmentEndWhole;
0 ignored issues
show
The constant PidLidAppointmentEndWhole was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
179
		$properties['flagdueby'] = 'PT_SYSTIME:PSETID_Common:' . PidLidReminderSignalTime;
0 ignored issues
show
The constant PidLidReminderSignalTime was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
180
		$properties['commonstart'] = 'PT_SYSTIME:PSETID_Common:0x8516';
181
		$properties['commonend'] = 'PT_SYSTIME:PSETID_Common:0x8517';
182
		$properties['recurring'] = 'PT_BOOLEAN:PSETID_Appointment:' . PidLidRecurring;
0 ignored issues
show
The constant PidLidRecurring was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
183
		$properties['clipstart'] = 'PT_SYSTIME:PSETID_Appointment:' . PidLidClipStart;
0 ignored issues
show
The constant PidLidClipStart was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
184
		$properties['clipend'] = 'PT_SYSTIME:PSETID_Appointment:' . PidLidClipEnd;
0 ignored issues
show
The constant PidLidClipEnd was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
185
		$properties['start_recur_date'] = 'PT_LONG:PSETID_Meeting:0xD';				// StartRecurTime
186
		$properties['start_recur_time'] = 'PT_LONG:PSETID_Meeting:0xE';				// StartRecurTime
187
		$properties['end_recur_date'] = 'PT_LONG:PSETID_Meeting:0xF';				// EndRecurDate
188
		$properties['end_recur_time'] = 'PT_LONG:PSETID_Meeting:0x10';				// EndRecurTime
189
		$properties['is_exception'] = 'PT_BOOLEAN:PSETID_Meeting:0xA';				// LID_IS_EXCEPTION
190
		$properties['apptreplyname'] = 'PT_STRING8:PSETID_Appointment:0x8230';
191
		// Propose new time properties
192
		$properties['proposed_start_whole'] = 'PT_SYSTIME:PSETID_Appointment:' . PidLidAppointmentProposedStartWhole;
0 ignored issues
show
The constant PidLidAppointmentProposedStartWhole was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
193
		$properties['proposed_end_whole'] = 'PT_SYSTIME:PSETID_Appointment:' . PidLidAppointmentProposedEndWhole;
0 ignored issues
show
The constant PidLidAppointmentProposedEndWhole was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
194
		$properties['proposed_duration'] = 'PT_LONG:PSETID_Appointment:0x8256';
195
		$properties['counter_proposal'] = 'PT_BOOLEAN:PSETID_Appointment:' . PidLidAppointmentCounterProposal;
0 ignored issues
show
The constant PidLidAppointmentCounterProposal was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
196
		$properties['recurring_pattern'] = 'PT_STRING8:PSETID_Appointment:0x8232';
197
		$properties['basedate'] = 'PT_SYSTIME:PSETID_Appointment:' . PidLidExceptionReplaceTime;
0 ignored issues
show
The constant PidLidExceptionReplaceTime was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
198
		$properties['meetingtype'] = 'PT_LONG:PSETID_Meeting:0x26';
199
		$properties['timezone_data'] = 'PT_BINARY:PSETID_Appointment:' . PidLidTimeZoneStruct;
0 ignored issues
show
The constant PidLidTimeZoneStruct was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
200
		$properties['timezone'] = 'PT_STRING8:PSETID_Appointment:' . PidLidTimeZoneDescription;
0 ignored issues
show
The constant PidLidTimeZoneDescription was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
201
		$properties['categories'] = 'PT_MV_STRING8:PS_PUBLIC_STRINGS:Keywords';
202
		$properties['private'] = 'PT_BOOLEAN:PSETID_Common:' . PidLidPrivate;
0 ignored issues
show
The constant PidLidPrivate was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
203
		$properties['alldayevent'] = 'PT_BOOLEAN:PSETID_Appointment:' . PidLidAppointmentSubType;
0 ignored issues
show
The constant PidLidAppointmentSubType was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
204
		$properties['toattendeesstring'] = 'PT_STRING8:PSETID_Appointment:0x823B';
205
		$properties['ccattendeesstring'] = 'PT_STRING8:PSETID_Appointment:0x823C';
206
207
		$this->proptags = getPropIdsFromStrings($store, $properties);
208
	}
209
210
	/**
211
	 * Sets the direct booking property. This is an alternative to the setting of the direct booking
212
	 * property through the constructor. However, setting it in the constructor is preferred.
213
	 *
214
	 * @param bool $directBookingSetting
215
	 */
216
	public function setDirectBooking($directBookingSetting): void {
217
		$this->enableDirectBooking = $directBookingSetting;
218
	}
219
220
	/**
221
	 * Returns TRUE if the message pointed to is an incoming meeting request and should
222
	 * therefore be replied to with doAccept or doDecline().
223
	 *
224
	 * @param string $messageClass message class to use for checking
225
	 *
226
	 * @return bool returns true if this is a meeting request else false
227
	 */
228
	public function isMeetingRequest($messageClass = false) {
229
		if ($messageClass === false) {
230
			$props = mapi_getprops($this->message, [PR_MESSAGE_CLASS]);
0 ignored issues
show
The function mapi_getprops was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

230
			$props = /** @scrutinizer ignore-call */ mapi_getprops($this->message, [PR_MESSAGE_CLASS]);
Loading history...
The constant PR_MESSAGE_CLASS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
231
			$messageClass = isset($props[PR_MESSAGE_CLASS]) ? $props[PR_MESSAGE_CLASS] : false;
232
		}
233
234
		if ($messageClass !== false && stripos($messageClass, 'ipm.schedule.meeting.request') === 0) {
235
			return true;
236
		}
237
238
		return false;
239
	}
240
241
	/**
242
	 * Returns TRUE if the message pointed to is a returning meeting request response.
243
	 *
244
	 * @param string $messageClass message class to use for checking
245
	 *
246
	 * @return bool returns true if this is a meeting request else false
247
	 */
248
	public function isMeetingRequestResponse($messageClass = false) {
249
		if ($messageClass === false) {
250
			$props = mapi_getprops($this->message, [PR_MESSAGE_CLASS]);
0 ignored issues
show
The constant PR_MESSAGE_CLASS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
The function mapi_getprops was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

250
			$props = /** @scrutinizer ignore-call */ mapi_getprops($this->message, [PR_MESSAGE_CLASS]);
Loading history...
251
			$messageClass = isset($props[PR_MESSAGE_CLASS]) ? $props[PR_MESSAGE_CLASS] : false;
252
		}
253
254
		if ($messageClass !== false && stripos($messageClass, 'ipm.schedule.meeting.resp') === 0) {
255
			return true;
256
		}
257
258
		return false;
259
	}
260
261
	/**
262
	 * Returns TRUE if the message pointed to is a cancellation request.
263
	 *
264
	 * @param string $messageClass message class to use for checking
265
	 *
266
	 * @return bool returns true if this is a meeting request else false
267
	 */
268
	public function isMeetingCancellation($messageClass = false) {
269
		if ($messageClass === false) {
270
			$props = mapi_getprops($this->message, [PR_MESSAGE_CLASS]);
0 ignored issues
show
The constant PR_MESSAGE_CLASS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
The function mapi_getprops was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

270
			$props = /** @scrutinizer ignore-call */ mapi_getprops($this->message, [PR_MESSAGE_CLASS]);
Loading history...
271
			$messageClass = isset($props[PR_MESSAGE_CLASS]) ? $props[PR_MESSAGE_CLASS] : false;
272
		}
273
274
		if ($messageClass !== false && stripos($messageClass, 'ipm.schedule.meeting.canceled') === 0) {
275
			return true;
276
		}
277
278
		return false;
279
	}
280
281
	/**
282
	 * Function is used to get the last update counter of meeting request.
283
	 *
284
	 * @return bool|int false when last_updatecounter not found else return last_updatecounter
285
	 */
286
	public function getLastUpdateCounter() {
287
		$calendarItemProps = mapi_getprops($this->message, [$this->proptags['last_updatecounter']]);
0 ignored issues
show
The function mapi_getprops was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

287
		$calendarItemProps = /** @scrutinizer ignore-call */ mapi_getprops($this->message, [$this->proptags['last_updatecounter']]);
Loading history...
288
		if (isset($calendarItemProps) && !empty($calendarItemProps)) {
289
			return $calendarItemProps[$this->proptags['last_updatecounter']];
290
		}
291
292
		return false;
293
	}
294
295
	/**
296
	 * Process an incoming meeting request response. This updates the appointment
297
	 * in your calendar to show whether the user has accepted or declined.
298
	 */
299
	public function processMeetingRequestResponse() {
300
		if (!$this->isMeetingRequestResponse()) {
301
			return;
302
		}
303
304
		if (!$this->isLocalOrganiser()) {
305
			return;
306
		}
307
308
		// Get information we need from the response message
309
		$messageprops = mapi_getprops($this->message, [
0 ignored issues
show
The function mapi_getprops was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

309
		$messageprops = /** @scrutinizer ignore-call */ mapi_getprops($this->message, [
Loading history...
310
			$this->proptags['goid'],
311
			$this->proptags['goid2'],
312
			PR_OWNER_APPT_ID,
0 ignored issues
show
The constant PR_OWNER_APPT_ID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
313
			PR_SENT_REPRESENTING_EMAIL_ADDRESS,
0 ignored issues
show
The constant PR_SENT_REPRESENTING_EMAIL_ADDRESS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
314
			PR_SENT_REPRESENTING_NAME,
0 ignored issues
show
The constant PR_SENT_REPRESENTING_NAME was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
315
			PR_SENT_REPRESENTING_ADDRTYPE,
0 ignored issues
show
The constant PR_SENT_REPRESENTING_ADDRTYPE was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
316
			PR_SENT_REPRESENTING_ENTRYID,
0 ignored issues
show
The constant PR_SENT_REPRESENTING_ENTRYID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
317
			PR_SENT_REPRESENTING_SEARCH_KEY,
0 ignored issues
show
The constant PR_SENT_REPRESENTING_SEARCH_KEY was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
318
			PR_MESSAGE_DELIVERY_TIME,
0 ignored issues
show
The constant PR_MESSAGE_DELIVERY_TIME was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
319
			PR_MESSAGE_CLASS,
0 ignored issues
show
The constant PR_MESSAGE_CLASS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
320
			PR_PROCESSED,
0 ignored issues
show
The constant PR_PROCESSED was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
321
			PR_RCVD_REPRESENTING_ENTRYID,
0 ignored issues
show
The constant PR_RCVD_REPRESENTING_ENTRYID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
322
			$this->proptags['proposed_start_whole'],
323
			$this->proptags['proposed_end_whole'],
324
			$this->proptags['proposed_duration'],
325
			$this->proptags['counter_proposal'],
326
			$this->proptags['attendee_critical_change'],
327
		]);
328
329
		$goid2 = $messageprops[$this->proptags['goid2']];
330
331
		if (!isset($goid2) || !isset($messageprops[PR_SENT_REPRESENTING_EMAIL_ADDRESS])) {
332
			return;
333
		}
334
335
		// Find basedate in GlobalID(0x3), this can be a response for an occurrence
336
		$basedate = $this->getBasedateFromGlobalID($messageprops[$this->proptags['goid']]);
337
338
		// check if delegate is processing the response
339
		if (isset($messageprops[PR_RCVD_REPRESENTING_ENTRYID])) {
340
			$delegatorStore = $this->getDelegatorStore($messageprops[PR_RCVD_REPRESENTING_ENTRYID], [PR_IPM_APPOINTMENT_ENTRYID]);
0 ignored issues
show
The constant PR_IPM_APPOINTMENT_ENTRYID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
341
			$userStore = $delegatorStore['store'];
342
		}
343
		else {
344
			$userStore = $this->store;
345
		}
346
347
		// check for calendar access
348
		if ($this->checkCalendarWriteAccess($userStore) !== true) {
349
			// Throw an exception that we don't have write permissions on calendar folder,
350
			// allow caller to fill the error message
351
			throw new MAPIException(null, MAPI_E_NO_ACCESS);
0 ignored issues
show
The constant MAPI_E_NO_ACCESS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
352
		}
353
354
		$calendarItem = $this->getCorrespondentCalendarItem(true);
355
356
		// Open the calendar items, and update all the recipients of the calendar item that match
357
		// the email address of the response.
358
		if ($calendarItem !== false) {
359
			$this->processResponse($userStore, $calendarItem, $basedate, $messageprops);
360
		}
361
	}
362
363
	/**
364
	 * Process every incoming MeetingRequest response.This updates the appointment
365
	 * in your calendar to show whether the user has accepted or declined.
366
	 *
367
	 * @param resource $store        contains the userStore in which the meeting is created
368
	 * @param mixed    $calendarItem resource of the calendar item for which this response has arrived
369
	 * @param mixed    $basedate     if present the create an exception
370
	 * @param array    $messageprops contains message properties
371
	 *
372
	 * @return null|false
373
	 */
374
	public function processResponse($store, $calendarItem, $basedate, $messageprops) {
375
		$senderentryid = $messageprops[PR_SENT_REPRESENTING_ENTRYID];
0 ignored issues
show
The constant PR_SENT_REPRESENTING_ENTRYID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
376
		$messageclass = $messageprops[PR_MESSAGE_CLASS];
0 ignored issues
show
The constant PR_MESSAGE_CLASS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
377
		$deliverytime = $messageprops[PR_MESSAGE_DELIVERY_TIME];
0 ignored issues
show
The constant PR_MESSAGE_DELIVERY_TIME was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
378
379
		// Open the calendar item, find the sender in the recipient table and update all the recipients of the calendar item that match
380
		// the email address of the response.
381
		$calendarItemProps = mapi_getprops($calendarItem, [$this->proptags['recurring'], PR_STORE_ENTRYID, PR_PARENT_ENTRYID, PR_ENTRYID, $this->proptags['updatecounter']]);
0 ignored issues
show
The function mapi_getprops was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

381
		$calendarItemProps = /** @scrutinizer ignore-call */ mapi_getprops($calendarItem, [$this->proptags['recurring'], PR_STORE_ENTRYID, PR_PARENT_ENTRYID, PR_ENTRYID, $this->proptags['updatecounter']]);
Loading history...
The constant PR_STORE_ENTRYID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
The constant PR_PARENT_ENTRYID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
382
383
		// check if meeting response is already processed
384
		if (isset($messageprops[PR_PROCESSED]) && $messageprops[PR_PROCESSED] == true) {
0 ignored issues
show
The constant PR_PROCESSED was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
385
			// meeting is already processed
386
			return;
387
		}
388
		mapi_setprops($this->message, [PR_PROCESSED => true]);
0 ignored issues
show
The function mapi_setprops was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

388
		/** @scrutinizer ignore-call */ 
389
  mapi_setprops($this->message, [PR_PROCESSED => true]);
Loading history...
389
		mapi_savechanges($this->message);
0 ignored issues
show
The function mapi_savechanges was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

389
		/** @scrutinizer ignore-call */ 
390
  mapi_savechanges($this->message);
Loading history...
390
391
		// if meeting is updated in organizer's calendar then we don't need to process
392
		// old response
393
		if ($this->isMeetingUpdated($basedate)) {
394
			return;
395
		}
396
397
		// If basedate is found, then create/modify exception msg and do processing
398
		if ($basedate && isset($calendarItemProps[$this->proptags['recurring']]) && $calendarItemProps[$this->proptags['recurring']] === true) {
399
			$recurr = new Recurrence($store, $calendarItem);
400
401
			// Copy properties from meeting request
402
			$exception_props = mapi_getprops($this->message, [
403
				PR_OWNER_APPT_ID,
0 ignored issues
show
The constant PR_OWNER_APPT_ID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
404
				$this->proptags['proposed_start_whole'],
405
				$this->proptags['proposed_end_whole'],
406
				$this->proptags['proposed_duration'],
407
				$this->proptags['counter_proposal'],
408
			]);
409
410
			// Create/modify exception
411
			if ($recurr->isException($basedate)) {
412
				$recurr->modifyException($exception_props, $basedate);
413
			}
414
			else {
415
				// When we are creating an exception we need copy recipients from main recurring item
416
				$recipTable = mapi_message_getrecipienttable($calendarItem);
0 ignored issues
show
The function mapi_message_getrecipienttable was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

416
				$recipTable = /** @scrutinizer ignore-call */ mapi_message_getrecipienttable($calendarItem);
Loading history...
417
				$recips = mapi_table_queryallrows($recipTable, $this->recipprops);
0 ignored issues
show
The function mapi_table_queryallrows was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

417
				$recips = /** @scrutinizer ignore-call */ mapi_table_queryallrows($recipTable, $this->recipprops);
Loading history...
418
419
				// Retrieve actual start/due dates from calendar item.
420
				$exception_props[$this->proptags['startdate']] = $recurr->getOccurrenceStart($basedate);
421
				$exception_props[$this->proptags['duedate']] = $recurr->getOccurrenceEnd($basedate);
422
423
				$recurr->createException($exception_props, $basedate, false, $recips);
424
			}
425
426
			mapi_savechanges($calendarItem);
427
428
			$attach = $recurr->getExceptionAttachment($basedate);
429
			if ($attach) {
430
				$recurringItem = $calendarItem;
431
				$calendarItem = mapi_attach_openobj($attach, MAPI_MODIFY);
0 ignored issues
show
The function mapi_attach_openobj was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

431
				$calendarItem = /** @scrutinizer ignore-call */ mapi_attach_openobj($attach, MAPI_MODIFY);
Loading history...
432
			}
433
			else {
434
				return false;
435
			}
436
		}
437
438
		// Get the recipients of the calendar item
439
		$reciptable = mapi_message_getrecipienttable($calendarItem);
440
		$recipients = mapi_table_queryallrows($reciptable, $this->recipprops);
441
442
		// FIXME we should look at the updatecounter property and compare it
443
		// to the counter in the recipient to see if this update is actually
444
		// newer than the status in the calendar item
445
		$found = false;
446
447
		$totalrecips = 0;
448
		$acceptedrecips = 0;
449
		foreach ($recipients as $recipient) {
450
			++$totalrecips;
451
			if (isset($recipient[PR_ENTRYID]) && $this->compareABEntryIDs($recipient[PR_ENTRYID], $senderentryid)) {
452
				$found = true;
453
454
				/*
455
				 * If value of attendee_critical_change on meeting response mail is less than PR_RECIPIENT_TRACKSTATUS_TIME
456
				 * on the corresponding recipientRow of meeting then we ignore this response mail.
457
				 */
458
				if (isset($recipient[PR_RECIPIENT_TRACKSTATUS_TIME]) && ($messageprops[$this->proptags['attendee_critical_change']] < $recipient[PR_RECIPIENT_TRACKSTATUS_TIME])) {
0 ignored issues
show
The constant PR_RECIPIENT_TRACKSTATUS_TIME was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
459
					continue;
460
				}
461
462
				// The email address matches, update the row
463
				$recipient[PR_RECIPIENT_TRACKSTATUS] = $this->getTrackStatus($messageclass);
0 ignored issues
show
The constant PR_RECIPIENT_TRACKSTATUS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
464
				if (isset($messageprops[$this->proptags['attendee_critical_change']])) {
465
					$recipient[PR_RECIPIENT_TRACKSTATUS_TIME] = $messageprops[$this->proptags['attendee_critical_change']];
466
				}
467
468
				// If this is a counter proposal, set the proposal properties in the recipient row
469
				if (isset($messageprops[$this->proptags['counter_proposal']]) && $messageprops[$this->proptags['counter_proposal']]) {
470
					$recipient[PR_RECIPIENT_PROPOSEDSTARTTIME] = $messageprops[$this->proptags['proposed_start_whole']];
0 ignored issues
show
The constant PR_RECIPIENT_PROPOSEDSTARTTIME was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
471
					$recipient[PR_RECIPIENT_PROPOSEDENDTIME] = $messageprops[$this->proptags['proposed_end_whole']];
0 ignored issues
show
The constant PR_RECIPIENT_PROPOSEDENDTIME was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
472
					$recipient[PR_RECIPIENT_PROPOSED] = $messageprops[$this->proptags['counter_proposal']];
0 ignored issues
show
The constant PR_RECIPIENT_PROPOSED was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
473
				}
474
475
				// Update the recipient information
476
				mapi_message_modifyrecipients($calendarItem, MODRECIP_REMOVE, [$recipient]);
0 ignored issues
show
The function mapi_message_modifyrecipients was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

476
				/** @scrutinizer ignore-call */ 
477
    mapi_message_modifyrecipients($calendarItem, MODRECIP_REMOVE, [$recipient]);
Loading history...
477
				mapi_message_modifyrecipients($calendarItem, MODRECIP_ADD, [$recipient]);
478
			}
479
			if (isset($recipient[PR_RECIPIENT_TRACKSTATUS]) && $recipient[PR_RECIPIENT_TRACKSTATUS] == olRecipientTrackStatusAccepted) {
480
				++$acceptedrecips;
481
			}
482
		}
483
484
		// If the recipient was not found in the original calendar item,
485
		// then add the recpient as a new optional recipient
486
		if (!$found) {
487
			$recipient = [];
488
			$recipient[PR_ENTRYID] = $messageprops[PR_SENT_REPRESENTING_ENTRYID];
489
			$recipient[PR_EMAIL_ADDRESS] = $messageprops[PR_SENT_REPRESENTING_EMAIL_ADDRESS];
0 ignored issues
show
The constant PR_EMAIL_ADDRESS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
The constant PR_SENT_REPRESENTING_EMAIL_ADDRESS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
490
			$recipient[PR_DISPLAY_NAME] = $messageprops[PR_SENT_REPRESENTING_NAME];
0 ignored issues
show
The constant PR_DISPLAY_NAME was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
The constant PR_SENT_REPRESENTING_NAME was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
491
			$recipient[PR_ADDRTYPE] = $messageprops[PR_SENT_REPRESENTING_ADDRTYPE];
0 ignored issues
show
The constant PR_SENT_REPRESENTING_ADDRTYPE was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
The constant PR_ADDRTYPE was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
492
			$recipient[PR_RECIPIENT_TYPE] = MAPI_CC;
0 ignored issues
show
The constant PR_RECIPIENT_TYPE was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
493
			$recipient[PR_SEARCH_KEY] = $messageprops[PR_SENT_REPRESENTING_SEARCH_KEY];
0 ignored issues
show
The constant PR_SEARCH_KEY was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
The constant PR_SENT_REPRESENTING_SEARCH_KEY was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
494
			$recipient[PR_RECIPIENT_TRACKSTATUS] = $this->getTrackStatus($messageclass);
495
			$recipient[PR_RECIPIENT_TRACKSTATUS_TIME] = $deliverytime;
496
497
			// If this is a counter proposal, set the proposal properties in the recipient row
498
			if (isset($messageprops[$this->proptags['counter_proposal']])) {
499
				$recipient[PR_RECIPIENT_PROPOSEDSTARTTIME] = $messageprops[$this->proptags['proposed_start_whole']];
500
				$recipient[PR_RECIPIENT_PROPOSEDENDTIME] = $messageprops[$this->proptags['proposed_end_whole']];
501
				$recipient[PR_RECIPIENT_PROPOSED] = $messageprops[$this->proptags['counter_proposal']];
502
			}
503
504
			mapi_message_modifyrecipients($calendarItem, MODRECIP_ADD, [$recipient]);
505
			++$totalrecips;
506
			if ($recipient[PR_RECIPIENT_TRACKSTATUS] == olRecipientTrackStatusAccepted) {
507
				++$acceptedrecips;
508
			}
509
		}
510
511
		// TODO: Update counter proposal number property on message
512
		/*
513
		If it is the first time this attendee has proposed a new date/time, increment the value of the PidLidAppointmentProposalNumber property on the organizer's meeting object, by 0x00000001. If this property did not previously exist on the organizer's meeting object, it MUST be set with a value of 0x00000001.
514
		*/
515
		// If this is a counter proposal, set the counter proposal indicator boolean
516
		if (isset($messageprops[$this->proptags['counter_proposal']])) {
517
			$props = [];
518
			if ($messageprops[$this->proptags['counter_proposal']]) {
519
				$props[$this->proptags['counter_proposal']] = true;
520
			}
521
			else {
522
				$props[$this->proptags['counter_proposal']] = false;
523
			}
524
525
			mapi_setprops($calendarItem, $props);
526
		}
527
528
		mapi_savechanges($calendarItem);
529
		if (isset($attach)) {
530
			mapi_savechanges($attach);
531
			mapi_savechanges($recurringItem);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $recurringItem does not seem to be defined for all execution paths leading up to this point.
Loading history...
532
		}
533
	}
534
535
	/**
536
	 * Process an incoming meeting request cancellation. This updates the
537
	 * appointment in your calendar to show that the meeting has been cancelled.
538
	 */
539
	public function processMeetingCancellation() {
540
		if (!$this->isMeetingCancellation()) {
541
			return;
542
		}
543
544
		if ($this->isLocalOrganiser()) {
545
			return;
546
		}
547
548
		if (!$this->isInCalendar()) {
549
			return;
550
		}
551
552
		$listProperties = $this->proptags;
553
		$listProperties['subject'] = PR_SUBJECT;
0 ignored issues
show
The constant PR_SUBJECT was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
554
		$listProperties['sent_representing_name'] = PR_SENT_REPRESENTING_NAME;
0 ignored issues
show
The constant PR_SENT_REPRESENTING_NAME was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
555
		$listProperties['sent_representing_address_type'] = PR_SENT_REPRESENTING_ADDRTYPE;
0 ignored issues
show
The constant PR_SENT_REPRESENTING_ADDRTYPE was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
556
		$listProperties['sent_representing_email_address'] = PR_SENT_REPRESENTING_EMAIL_ADDRESS;
0 ignored issues
show
The constant PR_SENT_REPRESENTING_EMAIL_ADDRESS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
557
		$listProperties['sent_representing_entryid'] = PR_SENT_REPRESENTING_ENTRYID;
0 ignored issues
show
The constant PR_SENT_REPRESENTING_ENTRYID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
558
		$listProperties['sent_representing_search_key'] = PR_SENT_REPRESENTING_SEARCH_KEY;
0 ignored issues
show
The constant PR_SENT_REPRESENTING_SEARCH_KEY was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
559
		$listProperties['rcvd_representing_name'] = PR_RCVD_REPRESENTING_NAME;
0 ignored issues
show
The constant PR_RCVD_REPRESENTING_NAME was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
560
		$listProperties['rcvd_representing_address_type'] = PR_RCVD_REPRESENTING_ADDRTYPE;
0 ignored issues
show
The constant PR_RCVD_REPRESENTING_ADDRTYPE was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
561
		$listProperties['rcvd_representing_email_address'] = PR_RCVD_REPRESENTING_EMAIL_ADDRESS;
0 ignored issues
show
The constant PR_RCVD_REPRESENTING_EMAIL_ADDRESS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
562
		$listProperties['rcvd_representing_entryid'] = PR_RCVD_REPRESENTING_ENTRYID;
0 ignored issues
show
The constant PR_RCVD_REPRESENTING_ENTRYID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
563
		$listProperties['rcvd_representing_search_key'] = PR_RCVD_REPRESENTING_SEARCH_KEY;
0 ignored issues
show
The constant PR_RCVD_REPRESENTING_SEARCH_KEY was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
564
		$messageProps = mapi_getprops($this->message, $listProperties);
0 ignored issues
show
The function mapi_getprops was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

564
		$messageProps = /** @scrutinizer ignore-call */ mapi_getprops($this->message, $listProperties);
Loading history...
565
566
		$goid = $messageProps[$this->proptags['goid']];	// GlobalID (0x3)
567
		if (!isset($goid)) {
568
			return;
569
		}
570
571
		// get delegator store, if delegate is processing this cancellation
572
		if (isset($messageProps[PR_RCVD_REPRESENTING_ENTRYID])) {
573
			$delegatorStore = $this->getDelegatorStore($messageProps[PR_RCVD_REPRESENTING_ENTRYID], [PR_IPM_APPOINTMENT_ENTRYID]);
0 ignored issues
show
The constant PR_IPM_APPOINTMENT_ENTRYID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
574
575
			$store = $delegatorStore['store'];
576
		}
577
		else {
578
			$store = $this->store;
579
		}
580
581
		// check for calendar access
582
		if ($this->checkCalendarWriteAccess($store) !== true) {
583
			// Throw an exception that we don't have write permissions on calendar folder,
584
			// allow caller to fill the error message
585
			throw new MAPIException(null, MAPI_E_NO_ACCESS);
0 ignored issues
show
The constant MAPI_E_NO_ACCESS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
586
		}
587
588
		$calendarItem = $this->getCorrespondentCalendarItem(true);
589
		$basedate = $this->getBasedateFromGlobalID($goid);
590
591
		if ($calendarItem !== false) {
592
			// if basedate is provided and we could not find the item then it could be that we are processing
593
			// an exception so get the exception and process it
594
			if ($basedate) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $basedate of type false|integer is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
595
				$calendarItemProps = mapi_getprops($calendarItem, [$this->proptags['recurring']]);
596
				if ($calendarItemProps[$this->proptags['recurring']] === true) {
597
					$recurr = new Recurrence($store, $calendarItem);
598
599
					// Set message class
600
					$messageProps[PR_MESSAGE_CLASS] = 'IPM.Appointment';
0 ignored issues
show
The constant PR_MESSAGE_CLASS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
601
602
					if ($recurr->isException($basedate)) {
603
						$recurr->modifyException($messageProps, $basedate);
604
					}
605
					else {
606
						$recurr->createException($messageProps, $basedate);
607
					}
608
				}
609
			}
610
			else {
611
				// set the properties of the cancellation object
612
				mapi_setprops($calendarItem, $messageProps);
0 ignored issues
show
The function mapi_setprops was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

612
				/** @scrutinizer ignore-call */ 
613
    mapi_setprops($calendarItem, $messageProps);
Loading history...
613
			}
614
615
			mapi_savechanges($calendarItem);
0 ignored issues
show
The function mapi_savechanges was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

615
			/** @scrutinizer ignore-call */ 
616
   mapi_savechanges($calendarItem);
Loading history...
616
		}
617
	}
618
619
	/**
620
	 * Returns true if the corresponding calendar items exists in the celendar folder for this
621
	 * meeting request/response/cancellation.
622
	 */
623
	public function isInCalendar(): bool {
624
		// @TODO check for deleted exceptions
625
		return $this->getCorrespondentCalendarItem(false) !== false;
626
	}
627
628
	/**
629
	 * Accepts the meeting request by moving the item to the calendar
630
	 * and sending a confirmation message back to the sender. If $tentative
631
	 * is TRUE, then the item is accepted tentatively. After accepting, you
632
	 * can't use this class instance any more. The message is closed. If you
633
	 * specify TRUE for 'move', then the item is actually moved (from your
634
	 * inbox probably) to the calendar. If you don't, it is copied into
635
	 * your calendar.
636
	 *
637
	 * @param bool  $tentative            true if user as tentative accepted the meeting
638
	 * @param bool  $sendresponse         true if a response has to be sent to organizer
639
	 * @param bool  $move                 true if the meeting request should be moved to the deleted items after processing
640
	 * @param mixed $newProposedStartTime contains starttime if user has proposed other time
641
	 * @param mixed $newProposedEndTime   contains endtime if user has proposed other time
642
	 * @param mixed $body
643
	 * @param mixed $userAction
644
	 * @param mixed $store
645
	 * @param mixed $basedate             start of day of occurrence for which user has accepted the recurrent meeting
646
	 * @param bool  $isImported           true to indicate that MR is imported from .ics or .vcs file else it false.
647
	 *
648
	 * @return bool|string $entryid entryid of item which created/updated in calendar
649
	 */
650
	public function doAccept($tentative, $sendresponse, $move, $newProposedStartTime = false, $newProposedEndTime = false, $body = false, $userAction = false, $store = false, $basedate = false, $isImported = false) {
651
		if ($this->isLocalOrganiser()) {
652
			return false;
653
		}
654
655
		// Remove any previous calendar items with this goid and appt id
656
		$messageprops = mapi_getprops($this->message, [PR_ENTRYID, PR_MESSAGE_CLASS, $this->proptags['goid'], $this->proptags['updatecounter'], PR_PROCESSED, PR_RCVD_REPRESENTING_ENTRYID, PR_SENDER_ENTRYID, PR_SENT_REPRESENTING_ENTRYID, PR_RECEIVED_BY_ENTRYID]);
0 ignored issues
show
The constant PR_MESSAGE_CLASS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
The constant PR_SENDER_ENTRYID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
The constant PR_RECEIVED_BY_ENTRYID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
The constant PR_SENT_REPRESENTING_ENTRYID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
The function mapi_getprops was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

656
		$messageprops = /** @scrutinizer ignore-call */ mapi_getprops($this->message, [PR_ENTRYID, PR_MESSAGE_CLASS, $this->proptags['goid'], $this->proptags['updatecounter'], PR_PROCESSED, PR_RCVD_REPRESENTING_ENTRYID, PR_SENDER_ENTRYID, PR_SENT_REPRESENTING_ENTRYID, PR_RECEIVED_BY_ENTRYID]);
Loading history...
The constant PR_PROCESSED was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
The constant PR_RCVD_REPRESENTING_ENTRYID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
657
658
		// If this meeting request is received by a delegate then open delegator's store.
659
		if (isset($messageprops[PR_RCVD_REPRESENTING_ENTRYID])) {
660
			$delegatorStore = $this->getDelegatorStore($messageprops[PR_RCVD_REPRESENTING_ENTRYID], [PR_IPM_APPOINTMENT_ENTRYID]);
0 ignored issues
show
The constant PR_IPM_APPOINTMENT_ENTRYID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
661
662
			$store = $delegatorStore['store'];
663
			$calFolder = $delegatorStore[PR_IPM_APPOINTMENT_ENTRYID];
664
		}
665
		else {
666
			$calFolder = $this->openDefaultCalendar();
667
			$store = $this->store;
668
		}
669
670
		// check for calendar access
671
		if ($this->checkCalendarWriteAccess($store) !== true) {
672
			// Throw an exception that we don't have write permissions on calendar folder,
673
			// allow caller to fill the error message
674
			throw new MAPIException(null, MAPI_E_NO_ACCESS);
0 ignored issues
show
The constant MAPI_E_NO_ACCESS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
675
		}
676
677
		// if meeting is out dated then don't process it
678
		if ($this->isMeetingRequest($messageprops[PR_MESSAGE_CLASS]) && $this->isMeetingOutOfDate()) {
679
			return false;
680
		}
681
682
		/*
683
		 *	if this function is called automatically with meeting request object then there will be
684
		 *	two possibilitites
685
		 *	1) meeting request is opened first time, in this case make a tentative appointment in
686
		 *		recipient's calendar
687
		 *	2) after this every subsequent request to open meeting request will not do any processing
688
		 */
689
		if ($this->isMeetingRequest($messageprops[PR_MESSAGE_CLASS]) && $userAction == false) {
690
			if (isset($messageprops[PR_PROCESSED]) && $messageprops[PR_PROCESSED] == true) {
691
				// if meeting request is already processed then don't do anything
692
				return false;
693
			}
694
695
			// if correspondent calendar item is already processed then don't do anything
696
			$calendarItem = $this->getCorrespondentCalendarItem();
697
			if ($calendarItem) {
698
				$calendarItemProps = mapi_getprops($calendarItem, [PR_PROCESSED]);
699
				if (isset($calendarItemProps[PR_PROCESSED]) && $calendarItemProps[PR_PROCESSED] == true) {
700
					// mark meeting-request mail as processed as well
701
					mapi_setprops($this->message, [PR_PROCESSED => true]);
0 ignored issues
show
The function mapi_setprops was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

701
					/** @scrutinizer ignore-call */ 
702
     mapi_setprops($this->message, [PR_PROCESSED => true]);
Loading history...
702
					mapi_savechanges($this->message);
0 ignored issues
show
The function mapi_savechanges was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

702
					/** @scrutinizer ignore-call */ 
703
     mapi_savechanges($this->message);
Loading history...
703
704
					return false;
705
				}
706
			}
707
		}
708
709
		// Retrieve basedate from globalID, if it is not received as argument
710
		if (!$basedate) {
711
			$basedate = $this->getBasedateFromGlobalID($messageprops[$this->proptags['goid']]);
712
		}
713
714
		// set counter proposal properties in calendar item when proposing new time
715
		$proposeNewTimeProps = [];
716
		if ($newProposedStartTime && $newProposedEndTime) {
717
			$proposeNewTimeProps[$this->proptags['proposed_start_whole']] = $newProposedStartTime;
718
			$proposeNewTimeProps[$this->proptags['proposed_end_whole']] = $newProposedEndTime;
719
			$proposeNewTimeProps[$this->proptags['proposed_duration']] = round($newProposedEndTime - $newProposedStartTime) / 60;
720
			$proposeNewTimeProps[$this->proptags['counter_proposal']] = true;
721
		}
722
723
		// While sender is receiver then we have to process the meeting request as per the intended busy status
724
		// instead of tentative, and accept the same as per the intended busystatus.
725
		$senderEntryId = isset($messageprops[PR_SENT_REPRESENTING_ENTRYID]) ? $messageprops[PR_SENT_REPRESENTING_ENTRYID] : $messageprops[PR_SENDER_ENTRYID];
726
		if (isset($messageprops[PR_RECEIVED_BY_ENTRYID]) && compareEntryIds($senderEntryId, $messageprops[PR_RECEIVED_BY_ENTRYID])) {
727
			$entryid = $this->accept(false, $sendresponse, $move, $proposeNewTimeProps, $body, true, $store, $calFolder, $basedate);
728
		}
729
		else {
730
			$entryid = $this->accept($tentative, $sendresponse, $move, $proposeNewTimeProps, $body, $userAction, $store, $calFolder, $basedate);
731
		}
732
733
		// if we have first time processed this meeting then set PR_PROCESSED property
734
		if ($this->isMeetingRequest($messageprops[PR_MESSAGE_CLASS]) && $userAction === false && $isImported === false) {
735
			if (!isset($messageprops[PR_PROCESSED]) || $messageprops[PR_PROCESSED] != true) {
736
				// set processed flag
737
				mapi_setprops($this->message, [PR_PROCESSED => true]);
738
				mapi_savechanges($this->message);
739
			}
740
		}
741
742
		return $entryid;
743
	}
744
745
	/**
746
	 * @param (float|mixed|true)[] $proposeNewTimeProps
747
	 * @param resource $calFolder
748
	 * @param mixed    $body
749
	 * @param mixed    $store
750
	 * @param mixed    $basedate
751
	 *
752
	 * @psalm-param array<float|mixed|true> $proposeNewTimeProps
753
	 */
754
	public function accept(bool $tentative, bool $sendresponse, bool $move, array $proposeNewTimeProps, $body, bool $userAction, $store, $calFolder, $basedate = false) {
755
		$messageprops = mapi_getprops($this->message);
0 ignored issues
show
The function mapi_getprops was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

755
		$messageprops = /** @scrutinizer ignore-call */ mapi_getprops($this->message);
Loading history...
756
		$isDelegate = isset($messageprops[PR_RCVD_REPRESENTING_NAME]);
0 ignored issues
show
The constant PR_RCVD_REPRESENTING_NAME was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
757
758
		if ($sendresponse) {
759
			$this->createResponse($tentative ? olResponseTentative : olResponseAccepted, $proposeNewTimeProps, $body, $store, $basedate, $calFolder);
760
		}
761
762
		/*
763
		 * Further processing depends on what user is receiving. User can receive recurring item, a single occurrence or a normal meeting.
764
		 * 1) If meeting req is of recurrence then we find all the occurrence in calendar because in past user might have received one or few occurrences.
765
		 * 2) If single occurrence then find occurrence itself using globalID and if item is not found then use cleanGlobalID to find main recurring item
766
		 * 3) Normal meeting req are handled normally as they were handled previously.
767
		 *
768
		 * Also user can respond(accept/decline) to item either from previewpane or from calendar by opening the item. If user is responding the meeting from previewpane
769
		 * and that item is not found in calendar then item is move else item is opened and all properties, attachments and recipient are copied from meeting request.
770
		 * If user is responding from calendar then item is opened and properties are set such as meetingstatus, responsestatus, busystatus etc.
771
		 */
772
		if ($this->isMeetingRequest($messageprops[PR_MESSAGE_CLASS])) {
0 ignored issues
show
The constant PR_MESSAGE_CLASS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
773
			// This meeting request item is recurring, so find all occurrences and saves them all as exceptions to this meeting request item.
774
			if (isset($messageprops[$this->proptags['recurring']]) && $messageprops[$this->proptags['recurring']] == true) {
775
				$calendarItem = false;
776
777
				// Find main recurring item based on GlobalID (0x3)
778
				$items = $this->findCalendarItems($messageprops[$this->proptags['goid2']], $calFolder);
779
				if (is_array($items)) {
780
					foreach ($items as $key => $entryid) {
781
						$calendarItem = mapi_msgstore_openentry($store, $entryid);
0 ignored issues
show
The function mapi_msgstore_openentry was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

781
						$calendarItem = /** @scrutinizer ignore-call */ mapi_msgstore_openentry($store, $entryid);
Loading history...
782
					}
783
				}
784
785
				$processed = false;
786
				if (!$calendarItem) {
787
					// Recurring item not found, so create new meeting in Calendar
788
					$calendarItem = mapi_folder_createmessage($calFolder);
0 ignored issues
show
The function mapi_folder_createmessage was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

788
					$calendarItem = /** @scrutinizer ignore-call */ mapi_folder_createmessage($calFolder);
Loading history...
789
				}
790
				else {
791
					// we have found the main recurring item, check if this meeting request is already processed
792
					if (isset($messageprops[PR_PROCESSED]) && $messageprops[PR_PROCESSED] == true) {
0 ignored issues
show
The constant PR_PROCESSED was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
793
						// only set required properties, other properties are already copied when processing this meeting request
794
						// for the first time
795
						$processed = true;
796
					}
797
				}
798
799
				if (!$processed) {
800
					// get all the properties and copy that to calendar item
801
					$props = mapi_getprops($this->message);
802
					// reset the PidLidMeetingType to Unspecified for outlook display the item
803
					$props[$this->proptags['meetingtype']] = mtgEmpty;
804
					/*
805
					 * the client which has sent this meeting request can generate wrong flagdueby
806
					 * time (mainly OL), so regenerate that property so we will always show reminder
807
					 * on right time
808
					 */
809
					if (isset($props[$this->proptags['reminderminutes']])) {
810
						$props[$this->proptags['flagdueby']] = $props[$this->proptags['startdate']] - ($props[$this->proptags['reminderminutes']] * 60);
811
					}
812
				}
813
				else {
814
					// only get required properties so we will not overwrite existing updated properties from calendar
815
					$props = mapi_getprops($this->message, [PR_ENTRYID]);
816
				}
817
818
				// While we applying updates of MR then all local categories will be removed,
819
				// So get the local categories of all occurrence before applying update from organiser.
820
				$localCategories = $this->getLocalCategories($calendarItem, $store, $calFolder);
821
822
				$props[PR_MESSAGE_CLASS] = 'IPM.Appointment';
823
				// When meeting requests are generated by third-party solutions, we might be missing the updatecounter property.
824
				if (!isset($props[$this->proptags['updatecounter']])) {
825
					$props[$this->proptags['updatecounter']] = 0;
826
				}
827
				$props[$this->proptags['meetingstatus']] = olMeetingReceived;
828
				// when we are automatically processing the meeting request set responsestatus to olResponseNotResponded
829
				$props[$this->proptags['responsestatus']] = $userAction ? ($tentative ? olResponseTentative : olResponseAccepted) : olResponseNotResponded;
830
831
				if (isset($props[$this->proptags['intendedbusystatus']])) {
832
					if ($tentative && $props[$this->proptags['intendedbusystatus']] !== fbFree) {
833
						$props[$this->proptags['busystatus']] = fbTentative;
834
					}
835
					else {
836
						$props[$this->proptags['busystatus']] = $props[$this->proptags['intendedbusystatus']];
837
					}
838
				// we already have intendedbusystatus value in $props so no need to copy it
839
				}
840
				else {
841
					$props[$this->proptags['busystatus']] = $tentative ? fbTentative : fbBusy;
842
				}
843
844
				if ($userAction) {
845
					$addrInfo = $this->getOwnerAddress($this->store);
846
847
					// if user has responded then set replytime and name
848
					$props[$this->proptags['replytime']] = time();
849
					if (!empty($addrInfo)) {
850
						// @FIXME conditionally set this property only for delegation case
851
						$props[$this->proptags['apptreplyname']] = $addrInfo[0];
852
					}
853
				}
854
855
				mapi_setprops($calendarItem, $props);
0 ignored issues
show
The function mapi_setprops was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

855
				/** @scrutinizer ignore-call */ 
856
    mapi_setprops($calendarItem, $props);
Loading history...
856
857
				// we have already processed attachments and recipients, so no need to do it again
858
				if (!$processed) {
859
					// Copy attachments too
860
					$this->replaceAttachments($this->message, $calendarItem);
861
					// Copy recipients too
862
					$this->replaceRecipients($this->message, $calendarItem, $isDelegate);
863
				}
864
865
				// Find all occurrences based on CleanGlobalID (0x23)
866
				// there will be no exceptions left if $processed is true, but even if it doesn't hurt to recheck
867
				$items = $this->findCalendarItems($messageprops[$this->proptags['goid2']], $calFolder, true);
868
				if (is_array($items)) {
869
					// Save all existing occurrence as exceptions
870
					foreach ($items as $entryid) {
871
						// Open occurrence
872
						$occurrenceItem = mapi_msgstore_openentry($store, $entryid);
873
874
						// Save occurrence into main recurring item as exception
875
						if ($occurrenceItem) {
876
							$occurrenceItemProps = mapi_getprops($occurrenceItem, [$this->proptags['goid'], $this->proptags['recurring']]);
877
878
							// Find basedate of occurrence item
879
							$basedate = $this->getBasedateFromGlobalID($occurrenceItemProps[$this->proptags['goid']]);
880
							if ($basedate && $occurrenceItemProps[$this->proptags['recurring']] != true) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $basedate of type false|integer is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
881
								$this->mergeException($calendarItem, $occurrenceItem, $basedate, $store);
882
							}
883
						}
884
					}
885
				}
886
887
				mapi_savechanges($calendarItem);
0 ignored issues
show
The function mapi_savechanges was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

887
				/** @scrutinizer ignore-call */ 
888
    mapi_savechanges($calendarItem);
Loading history...
888
889
				// After applying update of organiser all local categories of occurrence was removed,
890
				// So if local categories exist then apply it on respective occurrence.
891
				if (!empty($localCategories)) {
892
					$this->applyLocalCategories($calendarItem, $store, $localCategories);
893
				}
894
895
				if ($move) {
896
					// open wastebasket of currently logged in user and move the meeting request to it
897
					// for delegates this will be delegate's wastebasket folder
898
					$wastebasket = $this->openDefaultWastebasket($this->openDefaultStore());
899
					mapi_folder_copymessages($calFolder, [$props[PR_ENTRYID]], $wastebasket, MESSAGE_MOVE);
0 ignored issues
show
The function mapi_folder_copymessages was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

899
					/** @scrutinizer ignore-call */ 
900
     mapi_folder_copymessages($calFolder, [$props[PR_ENTRYID]], $wastebasket, MESSAGE_MOVE);
Loading history...
900
				}
901
902
				$entryid = $props[PR_ENTRYID];
903
			}
904
			else {
905
				/**
906
				 * This meeting request is not recurring, so can be an exception or normal meeting.
907
				 * If exception then find main recurring item and update exception
908
				 * If main recurring item is not found then put exception into Calendar as normal meeting.
909
				 */
910
				$calendarItem = false;
911
912
				// We found basedate in GlobalID of this meeting request, so this meeting request if for an occurrence.
913
				if ($basedate) {
914
					// Find main recurring item from CleanGlobalID of this meeting request
915
					$items = $this->findCalendarItems($messageprops[$this->proptags['goid2']], $calFolder);
916
					if (is_array($items)) {
917
						foreach ($items as $key => $entryid) {
918
							$calendarItem = mapi_msgstore_openentry($store, $entryid);
919
						}
920
					}
921
922
					// Main recurring item is found, so now update exception
923
					if ($calendarItem) {
924
						$this->acceptException($calendarItem, $this->message, $basedate, $move, $tentative, $userAction, $store, $isDelegate);
925
						$calendarItemProps = mapi_getprops($calendarItem, [PR_ENTRYID]);
926
						$entryid = $calendarItemProps[PR_ENTRYID];
927
					}
928
				}
929
930
				if (!$calendarItem) {
931
					$items = $this->findCalendarItems($messageprops[$this->proptags['goid']], $calFolder);
932
					if (is_array($items)) {
933
						// Get local categories before deleting MR.
934
						$message = mapi_msgstore_openentry($store, $items[0]);
935
						$localCategories = mapi_getprops($message, [$this->proptags['categories']]);
936
						mapi_folder_deletemessages($calFolder, $items);
0 ignored issues
show
The function mapi_folder_deletemessages was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

936
						/** @scrutinizer ignore-call */ 
937
      mapi_folder_deletemessages($calFolder, $items);
Loading history...
937
					}
938
939
					if ($move) {
940
						// All we have to do is open the default calendar,
941
						// set the message class correctly to be an appointment item
942
						// and move it to the calendar folder
943
						$sourcefolder = $this->openParentFolder();
944
945
						// create a new calendar message, and copy the message to there,
946
						// since we want to delete (move to wastebasket) the original message
947
						$old_entryid = mapi_getprops($this->message, [PR_ENTRYID]);
948
						$calmsg = mapi_folder_createmessage($calFolder);
949
						mapi_copyto($this->message, [], [], $calmsg); /* includes attachments and recipients */
0 ignored issues
show
The function mapi_copyto was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

949
						/** @scrutinizer ignore-call */ 
950
      mapi_copyto($this->message, [], [], $calmsg); /* includes attachments and recipients */
Loading history...
950
						// reset the PidLidMeetingType to Unspecified for outlook display the item
951
						$tmp_props = [];
952
						$tmp_props[$this->proptags['meetingtype']] = mtgEmpty;
953
						// OL needs this field always being set, or it will not display item
954
						$tmp_props[$this->proptags['recurring']] = false;
955
						mapi_setprops($calmsg, $tmp_props);
956
957
						// After creating new MR, If local categories exist then apply it on new MR.
958
						if (!empty($localCategories)) {
959
							mapi_setprops($calmsg, $localCategories);
960
						}
961
962
						$calItemProps = [];
963
						$calItemProps[PR_MESSAGE_CLASS] = 'IPM.Appointment';
964
965
						/*
966
						 * the client which has sent this meeting request can generate wrong flagdueby
967
						 * time (mainly OL), so regenerate that property so we will always show reminder
968
						 * on right time
969
						 */
970
						if (isset($messageprops[$this->proptags['reminderminutes']])) {
971
							$calItemProps[$this->proptags['flagdueby']] = $messageprops[$this->proptags['startdate']] - ($messageprops[$this->proptags['reminderminutes']] * 60);
972
						}
973
974
						if (isset($messageprops[$this->proptags['intendedbusystatus']])) {
975
							if ($tentative && $messageprops[$this->proptags['intendedbusystatus']] !== fbFree) {
976
								$calItemProps[$this->proptags['busystatus']] = fbTentative;
977
							}
978
							else {
979
								$calItemProps[$this->proptags['busystatus']] = $messageprops[$this->proptags['intendedbusystatus']];
980
							}
981
							$calItemProps[$this->proptags['intendedbusystatus']] = $messageprops[$this->proptags['intendedbusystatus']];
982
						}
983
						else {
984
							$calItemProps[$this->proptags['busystatus']] = $tentative ? fbTentative : fbBusy;
985
						}
986
987
						// when we are automatically processing the meeting request set responsestatus to olResponseNotResponded
988
						$calItemProps[$this->proptags['responsestatus']] = $userAction ? ($tentative ? olResponseTentative : olResponseAccepted) : olResponseNotResponded;
989
						if ($userAction) {
990
							$addrInfo = $this->getOwnerAddress($this->store);
991
992
							// if user has responded then set replytime and name
993
							$calItemProps[$this->proptags['replytime']] = time();
994
							if (!empty($addrInfo)) {
995
								$calItemProps[$this->proptags['apptreplyname']] = $addrInfo[0];
996
							}
997
						}
998
999
						$calItemProps[$this->proptags['recurring_pattern']] = '';
1000
						$calItemProps[$this->proptags['alldayevent']] = $calItemProps[$this->proptags['alldayevent']] ?? false;
1001
						$calItemProps[$this->proptags['private']] = $calItemProps[$this->proptags['private']] ?? false;
1002
						$calItemProps[$this->proptags['meetingstatus']] = $calItemProps[$this->proptags['meetingstatus']] ?? olMeetingReceived;
1003
						if (isset($calItemProps[$this->proptags['startdate']])) {
1004
							$calItemProps[$this->proptags['commonstart']] = $calItemProps[$this->proptags['startdate']];
1005
						}
1006
						if (isset($calItemProps[$this->proptags['duedate']])) {
1007
							$calItemProps[$this->proptags['commonend']] = $calItemProps[$this->proptags['duedate']];
1008
						}
1009
1010
						mapi_setprops($calmsg, $proposeNewTimeProps + $calItemProps);
1011
1012
						// get properties which stores owner information in meeting request mails
1013
						$props = mapi_getprops($calmsg, [
1014
							PR_SENT_REPRESENTING_ENTRYID,
0 ignored issues
show
The constant PR_SENT_REPRESENTING_ENTRYID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1015
							PR_SENT_REPRESENTING_NAME,
0 ignored issues
show
The constant PR_SENT_REPRESENTING_NAME was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1016
							PR_SENT_REPRESENTING_EMAIL_ADDRESS,
0 ignored issues
show
The constant PR_SENT_REPRESENTING_EMAIL_ADDRESS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1017
							PR_SENT_REPRESENTING_ADDRTYPE,
0 ignored issues
show
The constant PR_SENT_REPRESENTING_ADDRTYPE was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1018
							PR_SENT_REPRESENTING_SEARCH_KEY,
0 ignored issues
show
The constant PR_SENT_REPRESENTING_SEARCH_KEY was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1019
						]);
1020
1021
						// add owner to recipient table
1022
						$recips = [];
1023
						$this->addOrganizer($props, $recips);
1024
						mapi_message_modifyrecipients($calmsg, MODRECIP_ADD, $recips);
0 ignored issues
show
The function mapi_message_modifyrecipients was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

1024
						/** @scrutinizer ignore-call */ 
1025
      mapi_message_modifyrecipients($calmsg, MODRECIP_ADD, $recips);
Loading history...
1025
						mapi_savechanges($calmsg);
1026
1027
						// Move the message to the wastebasket
1028
						$wastebasket = $this->openDefaultWastebasket($this->openDefaultStore());
1029
						mapi_folder_copymessages($sourcefolder, [$old_entryid[PR_ENTRYID]], $wastebasket, MESSAGE_MOVE);
1030
1031
						$messageprops = mapi_getprops($calmsg, [PR_ENTRYID]);
1032
						$entryid = $messageprops[PR_ENTRYID];
1033
					}
1034
					else {
1035
						// Create a new appointment with duplicate properties and recipient, but as an IPM.Appointment
1036
						$new = mapi_folder_createmessage($calFolder);
1037
						$props = mapi_getprops($this->message);
1038
1039
						$props[$this->proptags['recurring_pattern']] = '';
1040
						$props[$this->proptags['alldayevent']] = $props[$this->proptags['alldayevent']] ?? false;
1041
						$props[$this->proptags['private']] = $props[$this->proptags['private']] ?? false;
1042
						$props[$this->proptags['meetingstatus']] = $props[$this->proptags['meetingstatus']] ?? olMeetingReceived;
1043
						if (isset($props[$this->proptags['startdate']])) {
1044
							$props[$this->proptags['commonstart']] = $props[$this->proptags['startdate']];
1045
						}
1046
						if (isset($props[$this->proptags['duedate']])) {
1047
							$props[$this->proptags['commonend']] = $props[$this->proptags['duedate']];
1048
						}
1049
1050
						$props[PR_MESSAGE_CLASS] = 'IPM.Appointment';
1051
						// reset the PidLidMeetingType to Unspecified for outlook display the item
1052
						$props[$this->proptags['meetingtype']] = mtgEmpty;
1053
						// OL needs this field always being set, or it will not display item
1054
						$props[$this->proptags['recurring']] = false;
1055
1056
						// After creating new MR, If local categories exist then apply it on new MR.
1057
						if (!empty($localCategories)) {
1058
							mapi_setprops($new, $localCategories);
1059
						}
1060
1061
						/*
1062
						 * the client which has sent this meeting request can generate wrong flagdueby
1063
						 * time (mainly OL), so regenerate that property so we will always show reminder
1064
						 * on right time
1065
						 */
1066
						if (isset($props[$this->proptags['reminderminutes']])) {
1067
							$props[$this->proptags['flagdueby']] = $props[$this->proptags['startdate']] - ($props[$this->proptags['reminderminutes']] * 60);
1068
						}
1069
1070
						// When meeting requests are generated by third-party solutions, we might be missing the updatecounter property.
1071
						if (!isset($props[$this->proptags['updatecounter']])) {
1072
							$props[$this->proptags['updatecounter']] = 0;
1073
						}
1074
						// when we are automatically processing the meeting request set responsestatus to olResponseNotResponded
1075
						$props[$this->proptags['responsestatus']] = $userAction ? ($tentative ? olResponseTentative : olResponseAccepted) : olResponseNotResponded;
1076
1077
						if (isset($props[$this->proptags['intendedbusystatus']])) {
1078
							if ($tentative && $props[$this->proptags['intendedbusystatus']] !== fbFree) {
1079
								$props[$this->proptags['busystatus']] = fbTentative;
1080
							}
1081
							else {
1082
								$props[$this->proptags['busystatus']] = $props[$this->proptags['intendedbusystatus']];
1083
							}
1084
						// we already have intendedbusystatus value in $props so no need to copy it
1085
						}
1086
						else {
1087
							$props[$this->proptags['busystatus']] = $tentative ? fbTentative : fbBusy;
1088
						}
1089
1090
						if ($userAction) {
1091
							$addrInfo = $this->getOwnerAddress($this->store);
1092
1093
							// if user has responded then set replytime and name
1094
							$props[$this->proptags['replytime']] = time();
1095
							if (!empty($addrInfo)) {
1096
								$props[$this->proptags['apptreplyname']] = $addrInfo[0];
1097
							}
1098
						}
1099
1100
						mapi_setprops($new, $proposeNewTimeProps + $props);
1101
1102
						$reciptable = mapi_message_getrecipienttable($this->message);
0 ignored issues
show
The function mapi_message_getrecipienttable was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

1102
						$reciptable = /** @scrutinizer ignore-call */ mapi_message_getrecipienttable($this->message);
Loading history...
1103
1104
						$recips = [];
1105
						// If delegate, then do not add the delegate in recipients
1106
						if ($isDelegate) {
1107
							$delegate = mapi_getprops($this->message, [PR_RECEIVED_BY_EMAIL_ADDRESS]);
0 ignored issues
show
The constant PR_RECEIVED_BY_EMAIL_ADDRESS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1108
							$res = [
1109
								RES_PROPERTY,
1110
								[
1111
									RELOP => RELOP_NE,
1112
									ULPROPTAG => PR_EMAIL_ADDRESS,
0 ignored issues
show
The constant PR_EMAIL_ADDRESS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1113
									VALUE => [PR_EMAIL_ADDRESS => $delegate[PR_RECEIVED_BY_EMAIL_ADDRESS]],
1114
								],
1115
							];
1116
							$recips = mapi_table_queryallrows($reciptable, $this->recipprops, $res);
0 ignored issues
show
The function mapi_table_queryallrows was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

1116
							$recips = /** @scrutinizer ignore-call */ mapi_table_queryallrows($reciptable, $this->recipprops, $res);
Loading history...
1117
						}
1118
						else {
1119
							$recips = mapi_table_queryallrows($reciptable, $this->recipprops);
1120
						}
1121
1122
						$this->addOrganizer($props, $recips);
1123
						mapi_message_modifyrecipients($new, MODRECIP_ADD, $recips);
1124
						mapi_savechanges($new);
1125
1126
						$props = mapi_getprops($new, [PR_ENTRYID]);
1127
						$entryid = $props[PR_ENTRYID];
1128
					}
1129
				}
1130
			}
1131
		}
1132
		else {
1133
			// Here only properties are set on calendaritem, because user is responding from calendar.
1134
			$props = [];
1135
			$props[$this->proptags['responsestatus']] = $tentative ? olResponseTentative : olResponseAccepted;
1136
1137
			if (isset($messageprops[$this->proptags['intendedbusystatus']])) {
1138
				if ($tentative && $messageprops[$this->proptags['intendedbusystatus']] !== fbFree) {
1139
					$props[$this->proptags['busystatus']] = fbTentative;
1140
				}
1141
				else {
1142
					$props[$this->proptags['busystatus']] = $messageprops[$this->proptags['intendedbusystatus']];
1143
				}
1144
				$props[$this->proptags['intendedbusystatus']] = $messageprops[$this->proptags['intendedbusystatus']];
1145
			}
1146
			else {
1147
				$props[$this->proptags['busystatus']] = $tentative ? fbTentative : fbBusy;
1148
			}
1149
1150
			$props[$this->proptags['meetingstatus']] = olMeetingReceived;
1151
1152
			$addrInfo = $this->getOwnerAddress($this->store);
1153
1154
			// if user has responded then set replytime and name
1155
			$props[$this->proptags['replytime']] = time();
1156
			if (!empty($addrInfo)) {
1157
				$props[$this->proptags['apptreplyname']] = $addrInfo[0];
1158
			}
1159
1160
			if ($basedate) {
1161
				$recurr = new Recurrence($store, $this->message);
1162
1163
				// Copy recipients list
1164
				$reciptable = mapi_message_getrecipienttable($this->message);
1165
				$recips = mapi_table_queryallrows($reciptable, $this->recipprops);
1166
1167
				if ($recurr->isException($basedate)) {
1168
					$recurr->modifyException($proposeNewTimeProps + $props, $basedate, $recips);
1169
				}
1170
				else {
1171
					$props[$this->proptags['startdate']] = $recurr->getOccurrenceStart($basedate);
1172
					$props[$this->proptags['duedate']] = $recurr->getOccurrenceEnd($basedate);
1173
1174
					$props[PR_SENT_REPRESENTING_EMAIL_ADDRESS] = $messageprops[PR_SENT_REPRESENTING_EMAIL_ADDRESS];
1175
					$props[PR_SENT_REPRESENTING_NAME] = $messageprops[PR_SENT_REPRESENTING_NAME];
1176
					$props[PR_SENT_REPRESENTING_ADDRTYPE] = $messageprops[PR_SENT_REPRESENTING_ADDRTYPE];
1177
					$props[PR_SENT_REPRESENTING_ENTRYID] = $messageprops[PR_SENT_REPRESENTING_ENTRYID];
1178
					$props[PR_SENT_REPRESENTING_SEARCH_KEY] = $messageprops[PR_SENT_REPRESENTING_SEARCH_KEY];
1179
1180
					$recurr->createException($proposeNewTimeProps + $props, $basedate, false, $recips);
1181
				}
1182
			}
1183
			else {
1184
				mapi_setprops($this->message, $proposeNewTimeProps + $props);
1185
			}
1186
			mapi_savechanges($this->message);
1187
1188
			$entryid = $messageprops[PR_ENTRYID];
1189
		}
1190
1191
		return $entryid;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $entryid does not seem to be defined for all execution paths leading up to this point.
Loading history...
1192
	}
1193
1194
	/**
1195
	 * Declines the meeting request by moving the item to the deleted
1196
	 * items folder and sending a decline message. After declining, you
1197
	 * can't use this class instance any more. The message is closed.
1198
	 * When an occurrence is decline then false is returned because that
1199
	 * occurrence is deleted not the recurring item.
1200
	 *
1201
	 * @param bool  $sendresponse true if a response has to be sent to organizer
1202
	 * @param mixed $basedate     if specified contains starttime of day of an occurrence
1203
	 * @param mixed $body
1204
	 *
1205
	 * @return bool true if item is deleted from Calendar else false
1206
	 */
1207
	public function doDecline($sendresponse, $basedate = false, $body = false) {
1208
		if ($this->isLocalOrganiser()) {
1209
			return false;
1210
		}
1211
1212
		$result = false;
1213
		$calendaritem = false;
1214
1215
		// Remove any previous calendar items with this goid and appt id
1216
		$messageprops = mapi_getprops($this->message, [$this->proptags['goid'], $this->proptags['goid2'], PR_RCVD_REPRESENTING_ENTRYID]);
0 ignored issues
show
The constant PR_RCVD_REPRESENTING_ENTRYID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
The function mapi_getprops was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

1216
		$messageprops = /** @scrutinizer ignore-call */ mapi_getprops($this->message, [$this->proptags['goid'], $this->proptags['goid2'], PR_RCVD_REPRESENTING_ENTRYID]);
Loading history...
1217
1218
		// If this meeting request is received by a delegate then open delegator's store.
1219
		if (isset($messageprops[PR_RCVD_REPRESENTING_ENTRYID])) {
1220
			$delegatorStore = $this->getDelegatorStore($messageprops[PR_RCVD_REPRESENTING_ENTRYID], [PR_IPM_APPOINTMENT_ENTRYID]);
0 ignored issues
show
The constant PR_IPM_APPOINTMENT_ENTRYID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1221
1222
			$store = $delegatorStore['store'];
1223
			$calFolder = $delegatorStore[PR_IPM_APPOINTMENT_ENTRYID];
1224
		}
1225
		else {
1226
			$calFolder = $this->openDefaultCalendar();
1227
			$store = $this->store;
1228
		}
1229
1230
		// check for calendar access before deleting the calendar item
1231
		if ($this->checkCalendarWriteAccess($store) !== true) {
1232
			// Throw an exception that we don't have write permissions on calendar folder,
1233
			// allow caller to fill the error message
1234
			throw new MAPIException(null, MAPI_E_NO_ACCESS);
0 ignored issues
show
The constant MAPI_E_NO_ACCESS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1235
		}
1236
1237
		$goid = $messageprops[$this->proptags['goid']];
1238
1239
		// First, find the items in the calendar by GlobalObjid (0x3)
1240
		$entryids = $this->findCalendarItems($goid, $calFolder);
1241
1242
		if (!$basedate) {
1243
			$basedate = $this->getBasedateFromGlobalID($goid);
1244
		}
1245
1246
		if ($sendresponse) {
1247
			$this->createResponse(olResponseDeclined, [], $body, $store, $basedate, $calFolder);
1248
		}
1249
1250
		if ($basedate) {
1251
			// use CleanGlobalObjid (0x23)
1252
			$calendaritems = $this->findCalendarItems($messageprops[$this->proptags['goid2']], $calFolder);
1253
1254
			if (is_array($calendaritems)) {
1255
				foreach ($calendaritems as $entryid) {
1256
					// Open each calendar item and set the properties of the cancellation object
1257
					$calendaritem = mapi_msgstore_openentry($store, $entryid);
0 ignored issues
show
The function mapi_msgstore_openentry was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

1257
					$calendaritem = /** @scrutinizer ignore-call */ mapi_msgstore_openentry($store, $entryid);
Loading history...
1258
1259
					// Recurring item is found, now delete exception
1260
					if ($calendaritem) {
1261
						$this->doRemoveExceptionFromCalendar($basedate, $calendaritem, $store);
1262
						$result = true;
1263
					}
1264
				}
1265
			}
1266
1267
			if ($this->isMeetingRequest()) {
1268
				$calendaritem = false;
1269
			}
1270
		}
1271
1272
		if (!$calendaritem) {
1273
			$calendar = $this->openDefaultCalendar($store);
1274
1275
			if (!empty($entryids)) {
1276
				mapi_folder_deletemessages($calendar, $entryids);
0 ignored issues
show
The function mapi_folder_deletemessages was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

1276
				/** @scrutinizer ignore-call */ 
1277
    mapi_folder_deletemessages($calendar, $entryids);
Loading history...
1277
			}
1278
1279
			// All we have to do to decline, is to move the item to the waste basket
1280
			$wastebasket = $this->openDefaultWastebasket($this->openDefaultStore());
1281
			$sourcefolder = $this->openParentFolder();
1282
1283
			$messageprops = mapi_getprops($this->message, [PR_ENTRYID]);
1284
1285
			// Release the message
1286
			$this->message = null;
1287
1288
			// Move the message to the waste basket
1289
			mapi_folder_copymessages($sourcefolder, [$messageprops[PR_ENTRYID]], $wastebasket, MESSAGE_MOVE);
0 ignored issues
show
The function mapi_folder_copymessages was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

1289
			/** @scrutinizer ignore-call */ 
1290
   mapi_folder_copymessages($sourcefolder, [$messageprops[PR_ENTRYID]], $wastebasket, MESSAGE_MOVE);
Loading history...
1290
1291
			$result = true;
1292
		}
1293
1294
		return $result;
1295
	}
1296
1297
	/**
1298
	 * Removes a meeting request from the calendar when the user presses the
1299
	 * 'remove from calendar' button in response to a meeting cancellation.
1300
	 *
1301
	 * @param mixed $basedate if specified contains starttime of day of an occurrence
1302
	 *
1303
	 * @return null|false
1304
	 */
1305
	public function doRemoveFromCalendar($basedate) {
1306
		if ($this->isLocalOrganiser()) {
1307
			return false;
1308
		}
1309
1310
		$messageprops = mapi_getprops($this->message, [PR_ENTRYID, $this->proptags['goid'], PR_RCVD_REPRESENTING_ENTRYID, PR_MESSAGE_CLASS]);
0 ignored issues
show
The constant PR_MESSAGE_CLASS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
The function mapi_getprops was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

1310
		$messageprops = /** @scrutinizer ignore-call */ mapi_getprops($this->message, [PR_ENTRYID, $this->proptags['goid'], PR_RCVD_REPRESENTING_ENTRYID, PR_MESSAGE_CLASS]);
Loading history...
The constant PR_RCVD_REPRESENTING_ENTRYID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1311
1312
		$goid = $messageprops[$this->proptags['goid']];
1313
1314
		if (isset($messageprops[PR_RCVD_REPRESENTING_ENTRYID])) {
1315
			$delegatorStore = $this->getDelegatorStore($messageprops[PR_RCVD_REPRESENTING_ENTRYID], [PR_IPM_APPOINTMENT_ENTRYID]);
0 ignored issues
show
The constant PR_IPM_APPOINTMENT_ENTRYID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1316
1317
			$store = $delegatorStore['store'];
1318
			$calFolder = $delegatorStore[PR_IPM_APPOINTMENT_ENTRYID];
1319
		}
1320
		else {
1321
			$store = $this->store;
1322
			$calFolder = $this->openDefaultCalendar();
1323
		}
1324
1325
		// check for calendar access before deleting the calendar item
1326
		if ($this->checkCalendarWriteAccess($store) !== true) {
1327
			// Throw an exception that we don't have write permissions on calendar folder,
1328
			// allow caller to fill the error message
1329
			throw new MAPIException(null, MAPI_E_NO_ACCESS);
0 ignored issues
show
The constant MAPI_E_NO_ACCESS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1330
		}
1331
1332
		$wastebasket = $this->openDefaultWastebasket($this->openDefaultStore());
1333
		// get the source folder of the meeting message
1334
		$sourcefolder = $this->openParentFolder();
1335
1336
		// Check if the message is a meeting request in the inbox or a calendaritem by checking the message class
1337
		if ($this->isMeetingCancellation($messageprops[PR_MESSAGE_CLASS])) {
1338
			// get the basedate to check for exception
1339
			$basedate = $this->getBasedateFromGlobalID($goid);
1340
1341
			$calendarItem = $this->getCorrespondentCalendarItem(true);
1342
1343
			if ($calendarItem !== false) {
1344
				// basedate is provided so open exception
1345
				if ($basedate) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $basedate of type false|integer is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
1346
					$exception = $this->getExceptionItem($calendarItem, $basedate);
1347
1348
					if ($exception !== false) {
0 ignored issues
show
The condition $exception !== false is always true.
Loading history...
1349
						// exception found, remove it from calendar
1350
						$this->doRemoveExceptionFromCalendar($basedate, $calendarItem, $store);
1351
					}
1352
				}
1353
				else {
1354
					// remove normal / recurring series from calendar
1355
					$entryids = mapi_getprops($calendarItem, [PR_ENTRYID]);
1356
1357
					$entryids = [$entryids[PR_ENTRYID]];
1358
1359
					mapi_folder_copymessages($calFolder, $entryids, $wastebasket, MESSAGE_MOVE);
0 ignored issues
show
The function mapi_folder_copymessages was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

1359
					/** @scrutinizer ignore-call */ 
1360
     mapi_folder_copymessages($calFolder, $entryids, $wastebasket, MESSAGE_MOVE);
Loading history...
1360
				}
1361
			}
1362
1363
			// Release the message, because we are going to move it to wastebasket
1364
			$this->message = null;
1365
1366
			// Move the cancellation mail to wastebasket
1367
			mapi_folder_copymessages($sourcefolder, [$messageprops[PR_ENTRYID]], $wastebasket, MESSAGE_MOVE);
1368
		}
1369
		else {
1370
			// Here only properties are set on calendaritem, because user is responding from calendar.
1371
			if ($basedate) {
1372
				// remove the occurrence
1373
				$this->doRemoveExceptionFromCalendar($basedate, $this->message, $store);
1374
			}
1375
			else {
1376
				// remove normal/recurring meeting item.
1377
				// Move the message to the waste basket
1378
				mapi_folder_copymessages($sourcefolder, [$messageprops[PR_ENTRYID]], $wastebasket, MESSAGE_MOVE);
1379
			}
1380
		}
1381
	}
1382
1383
	/**
1384
	 * Function can be used to cancel any existing meeting and send cancellation mails to attendees.
1385
	 * Should only be called from meeting object from calendar.
1386
	 *
1387
	 * @param mixed $basedate (optional) basedate of occurrence which should be cancelled
1388
	 *
1389
	 * @FIXME cancellation mail is also sent to attendee which has declined the meeting
1390
	 * @FIXME don't send canellation mail when cancelling meeting from past
1391
	 */
1392
	public function doCancelInvitation($basedate = false) {
1393
		if (!$this->isLocalOrganiser()) {
1394
			return;
1395
		}
1396
1397
		// check write access for delegate
1398
		if ($this->checkCalendarWriteAccess($this->store) !== true) {
1399
			// Throw an exception that we don't have write permissions on calendar folder,
1400
			// error message will be filled by module
1401
			throw new MAPIException(null, MAPI_E_NO_ACCESS);
0 ignored issues
show
The constant MAPI_E_NO_ACCESS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1402
		}
1403
1404
		$messageProps = mapi_getprops($this->message, [PR_ENTRYID, $this->proptags['recurring']]);
0 ignored issues
show
The function mapi_getprops was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

1404
		$messageProps = /** @scrutinizer ignore-call */ mapi_getprops($this->message, [PR_ENTRYID, $this->proptags['recurring']]);
Loading history...
1405
1406
		if (isset($messageProps[$this->proptags['recurring']]) && $messageProps[$this->proptags['recurring']] === true) {
1407
			// cancellation of recurring series or one occurrence
1408
			$recurrence = new Recurrence($this->store, $this->message);
1409
1410
			// if basedate is specified then we are cancelling only one occurrence, so create exception for that occurrence
1411
			if ($basedate) {
1412
				$recurrence->createException([], $basedate, true);
1413
			}
1414
1415
			// update the meeting request
1416
			$this->updateMeetingRequest();
1417
1418
			// send cancellation mails
1419
			$this->sendMeetingRequest(true, dgettext('zarafa', 'Canceled') . ': ', $basedate);
1420
1421
			// save changes in the message
1422
			mapi_savechanges($this->message);
0 ignored issues
show
The function mapi_savechanges was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

1422
			/** @scrutinizer ignore-call */ 
1423
   mapi_savechanges($this->message);
Loading history...
1423
		}
1424
		else {
1425
			// cancellation of normal meeting request
1426
			// Send the cancellation
1427
			$this->updateMeetingRequest();
1428
			$this->sendMeetingRequest(true, dgettext('zarafa', 'Canceled') . ': ');
1429
1430
			// save changes in the message
1431
			mapi_savechanges($this->message);
1432
		}
1433
1434
		// if basedate is specified then we have already created exception of it so nothing should be done now
1435
		// but when cancelling normal / recurring meeting request we need to remove meeting from calendar
1436
		if ($basedate === false) {
1437
			// get the wastebasket folder, for delegate this will give wastebasket of delegate
1438
			$wastebasket = $this->openDefaultWastebasket($this->openDefaultStore());
1439
1440
			// get the source folder of the meeting message
1441
			$sourcefolder = $this->openParentFolder();
1442
1443
			// Move the message to the deleted items
1444
			mapi_folder_copymessages($sourcefolder, [$messageProps[PR_ENTRYID]], $wastebasket, MESSAGE_MOVE);
0 ignored issues
show
The function mapi_folder_copymessages was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

1444
			/** @scrutinizer ignore-call */ 
1445
   mapi_folder_copymessages($sourcefolder, [$messageProps[PR_ENTRYID]], $wastebasket, MESSAGE_MOVE);
Loading history...
1445
		}
1446
	}
1447
1448
	/**
1449
	 * Convert epoch to MAPI FileTime, number of 100-nanosecond units since
1450
	 * the start of January 1, 1601.
1451
	 * https://msdn.microsoft.com/en-us/library/office/cc765906.aspx.
1452
	 *
1453
	 * @param int $epoch the current epoch
1454
	 *
1455
	 * @return int the MAPI FileTime equalevent to the given epoch time
1456
	 */
1457
	public function epochToMapiFileTime($epoch) {
1458
		$nanoseconds_between_epoch = 116444736000000000;
1459
1460
		return ($epoch * 10000000) + $nanoseconds_between_epoch;
1461
	}
1462
1463
	/**
1464
	 * Sets the properties in the message so that is can be sent
1465
	 * as a meeting request. The caller has to submit the message. This
1466
	 * is only used for new MeetingRequests. Pass the appointment item as $message
1467
	 * in the constructor to do this.
1468
	 *
1469
	 * @param mixed $basedate
1470
	 */
1471
	public function setMeetingRequest($basedate = false): void {
1472
		$props = mapi_getprops($this->message, [$this->proptags['updatecounter']]);
0 ignored issues
show
The function mapi_getprops was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

1472
		$props = /** @scrutinizer ignore-call */ mapi_getprops($this->message, [$this->proptags['updatecounter']]);
Loading history...
1473
1474
		// Create a new global id for this item
1475
		// https://msdn.microsoft.com/en-us/library/ee160198(v=exchg.80).aspx
1476
		$goid = pack('H*', '040000008200E00074C5B7101A82E00800000000');
1477
		/*
1478
		$year = gmdate('Y');
1479
		$month = gmdate('n');
1480
		$day = gmdate('j');
1481
		$goid .= pack('n', $year);
1482
		$goid .= pack('C', $month);
1483
		$goid .= pack('C', $day);
1484
		*/
1485
		// Creation Time
1486
		$time = $this->epochToMapiFileTime(time());
1487
		$goid .= pack('V', $time & 0xFFFFFFFF);
1488
		$goid .= pack('V', $time >> 32);
1489
		// 8 Zeros
1490
		$goid .= pack('H*', '0000000000000000');
1491
		// Length of the random data
1492
		$goid .= pack('V', 16);
1493
		// Random data.
1494
		for ($i = 0; $i < 16; ++$i) {
1495
			$goid .= chr(rand(0, 255));
1496
		}
1497
1498
		// Create a new appointment id for this item
1499
		$apptid = rand();
1500
1501
		$props[PR_OWNER_APPT_ID] = $apptid;
0 ignored issues
show
The constant PR_OWNER_APPT_ID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1502
		$props[PR_ICON_INDEX] = 1026;
0 ignored issues
show
The constant PR_ICON_INDEX was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1503
		$props[$this->proptags['goid']] = $goid;
1504
		$props[$this->proptags['goid2']] = $goid;
1505
1506
		if (!isset($props[$this->proptags['updatecounter']])) {
1507
			$props[$this->proptags['updatecounter']] = 0;			// OL also starts sequence no with zero.
1508
			$props[$this->proptags['last_updatecounter']] = 0;
1509
		}
1510
1511
		mapi_setprops($this->message, $props);
0 ignored issues
show
The function mapi_setprops was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

1511
		/** @scrutinizer ignore-call */ 
1512
  mapi_setprops($this->message, $props);
Loading history...
1512
	}
1513
1514
	/**
1515
	 * Sends a meeting request by copying it to the outbox, converting
1516
	 * the message class, adding some properties that are required only
1517
	 * for sending the message and submitting the message. Set cancel to
1518
	 * true if you wish to completely cancel the meeting request. You can
1519
	 * specify an optional 'prefix' to prefix the sent message, which is normally
1520
	 * 'Canceled: '.
1521
	 *
1522
	 * @param mixed $cancel
1523
	 * @param mixed $prefix
1524
	 * @param mixed $basedate
1525
	 * @param mixed $modifiedRecips
1526
	 * @param mixed $deletedRecips
1527
	 *
1528
	 * @return (int|mixed)[]|true
1529
	 *
1530
	 * @psalm-return array{error: 1|3|4, displayname: mixed}|true
1531
	 */
1532
	public function sendMeetingRequest($cancel, $prefix = false, $basedate = false, $modifiedRecips = false, $deletedRecips = false) {
1533
		$this->includesResources = false;
1534
		$this->nonAcceptingResources = [];
1535
1536
		// Get the properties of the message
1537
		$messageprops = mapi_getprops($this->message, [$this->proptags['recurring']]);
0 ignored issues
show
The function mapi_getprops was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

1537
		$messageprops = /** @scrutinizer ignore-call */ mapi_getprops($this->message, [$this->proptags['recurring']]);
Loading history...
1538
1539
		/*
1540
		 * Submit message to non-resource recipients
1541
		 */
1542
		// Set BusyStatus to olTentative (1)
1543
		// Set MeetingStatus to olMeetingReceived
1544
		// Set ResponseStatus to olResponseNotResponded
1545
1546
		/*
1547
		 * While sending recurrence meeting exceptions are not sent as attachments
1548
		 * because first all exceptions are sent and then recurrence meeting is sent.
1549
		 */
1550
		if (isset($messageprops[$this->proptags['recurring']]) && $messageprops[$this->proptags['recurring']] && !$basedate) {
1551
			// Book resource
1552
			$this->bookResources($this->message, $cancel, $prefix);
1553
1554
			if (!$this->errorSetResource) {
1555
				$recurr = new Recurrence($this->openDefaultStore(), $this->message);
0 ignored issues
show
It seems like $this->openDefaultStore() can also be of type false; however, parameter $store of Recurrence::__construct() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1555
				$recurr = new Recurrence(/** @scrutinizer ignore-type */ $this->openDefaultStore(), $this->message);
Loading history...
1556
1557
				// First send meetingrequest for recurring item
1558
				$this->submitMeetingRequest($this->message, $cancel, $prefix, false, $recurr, false, $modifiedRecips, $deletedRecips);
1559
1560
				// Then send all meeting request for all exceptions
1561
				$exceptions = $recurr->getAllExceptions();
1562
				if ($exceptions) {
1563
					foreach ($exceptions as $exceptionBasedate) {
1564
						$attach = $recurr->getExceptionAttachment($exceptionBasedate);
1565
1566
						if ($attach) {
1567
							$occurrenceItem = mapi_attach_openobj($attach, MAPI_MODIFY);
0 ignored issues
show
The function mapi_attach_openobj was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

1567
							$occurrenceItem = /** @scrutinizer ignore-call */ mapi_attach_openobj($attach, MAPI_MODIFY);
Loading history...
1568
							$this->submitMeetingRequest($occurrenceItem, $cancel, false, $exceptionBasedate, $recurr, false, $modifiedRecips, $deletedRecips);
1569
							mapi_savechanges($attach);
0 ignored issues
show
The function mapi_savechanges was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

1569
							/** @scrutinizer ignore-call */ 
1570
       mapi_savechanges($attach);
Loading history...
1570
						}
1571
					}
1572
				}
1573
			}
1574
		}
1575
		else {
1576
			// Basedate found, an exception is to be sent
1577
			if ($basedate) {
1578
				$recurr = new Recurrence($this->openDefaultStore(), $this->message);
1579
1580
				if ($cancel) {
1581
					// @TODO: remove occurrence from Resource's Calendar if resource was booked for whole series
1582
					$this->submitMeetingRequest($this->message, $cancel, $prefix, $basedate, $recurr, false);
1583
				}
1584
				else {
1585
					$attach = $recurr->getExceptionAttachment($basedate);
1586
1587
					if ($attach) {
1588
						$occurrenceItem = mapi_attach_openobj($attach, MAPI_MODIFY);
1589
1590
						// Book resource for this occurrence
1591
						$resourceRecipData = $this->bookResources($occurrenceItem, $cancel, $prefix, $basedate);
0 ignored issues
show
The assignment to $resourceRecipData is dead and can be removed.
Loading history...
1592
1593
						if (!$this->errorSetResource) {
1594
							// Save all previous changes
1595
							mapi_savechanges($this->message);
1596
1597
							$this->submitMeetingRequest($occurrenceItem, $cancel, $prefix, $basedate, $recurr, true, $modifiedRecips, $deletedRecips);
1598
							mapi_savechanges($occurrenceItem);
1599
							mapi_savechanges($attach);
1600
						}
1601
					}
1602
				}
1603
			}
1604
			else {
1605
				// This is normal meeting
1606
				$resourceRecipData = $this->bookResources($this->message, $cancel, $prefix);
1607
1608
				if (!$this->errorSetResource) {
1609
					$this->submitMeetingRequest($this->message, $cancel, $prefix, false, false, false, $modifiedRecips, $deletedRecips);
1610
				}
1611
			}
1612
		}
1613
1614
		if (isset($this->errorSetResource) && $this->errorSetResource) {
1615
			return [
1616
				'error' => $this->errorSetResource,
1617
				'displayname' => $this->recipientDisplayname,
1618
			];
1619
		}
1620
1621
		return true;
1622
	}
1623
1624
	/**
1625
	 * Updates the message after an update has been performed (for example,
1626
	 * changing the time of the meeting). This must be called before re-sending
1627
	 * the meeting request. You can also call this function instead of 'setMeetingRequest()'
1628
	 * as it will automatically call setMeetingRequest on this object if it is the first
1629
	 * call to this function.
1630
	 *
1631
	 * @param mixed $basedate
1632
	 */
1633
	public function updateMeetingRequest($basedate = false): void {
1634
		$messageprops = mapi_getprops($this->message, [$this->proptags['last_updatecounter'], $this->proptags['goid']]);
0 ignored issues
show
The function mapi_getprops was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

1634
		$messageprops = /** @scrutinizer ignore-call */ mapi_getprops($this->message, [$this->proptags['last_updatecounter'], $this->proptags['goid']]);
Loading history...
1635
1636
		if (!isset($messageprops[$this->proptags['goid']])) {
1637
			$this->setMeetingRequest($basedate);
1638
		}
1639
		else {
1640
			$counter = $messageprops[$this->proptags['last_updatecounter']] + 1;
1641
1642
			// increment value of last_updatecounter, last_updatecounter will be common for recurring series
1643
			// so even if you sending an exception only you need to update the last_updatecounter in the recurring series message
1644
			// this way we can make sure that every time we will be using a uniwue number for every operation
1645
			mapi_setprops($this->message, [$this->proptags['last_updatecounter'] => $counter]);
0 ignored issues
show
The function mapi_setprops was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

1645
			/** @scrutinizer ignore-call */ 
1646
   mapi_setprops($this->message, [$this->proptags['last_updatecounter'] => $counter]);
Loading history...
1646
		}
1647
	}
1648
1649
	/**
1650
	 * Returns TRUE if we are the organiser of the meeting. Can be used with any type of meeting object.
1651
	 */
1652
	public function isLocalOrganiser(): bool {
1653
		$props = mapi_getprops($this->message, [$this->proptags['goid'], PR_MESSAGE_CLASS]);
0 ignored issues
show
The constant PR_MESSAGE_CLASS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
The function mapi_getprops was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

1653
		$props = /** @scrutinizer ignore-call */ mapi_getprops($this->message, [$this->proptags['goid'], PR_MESSAGE_CLASS]);
Loading history...
1654
1655
		if (!$this->isMeetingRequest($props[PR_MESSAGE_CLASS]) && !$this->isMeetingRequestResponse($props[PR_MESSAGE_CLASS]) && !$this->isMeetingCancellation($props[PR_MESSAGE_CLASS])) {
1656
			// we are checking with calendar item
1657
			$calendarItem = $this->message;
1658
		}
1659
		else {
1660
			// we are checking with meeting request / response / cancellation mail
1661
			// get calendar items
1662
			$calendarItem = $this->getCorrespondentCalendarItem(true);
1663
		}
1664
1665
		// even if we have received request/response for exception/occurrence then also
1666
		// we can check recurring series for organizer, no need to check with exception/occurrence
1667
1668
		if ($calendarItem !== false) {
1669
			$messageProps = mapi_getprops($calendarItem, [$this->proptags['responsestatus']]);
1670
1671
			if (isset($messageProps[$this->proptags['responsestatus']]) && $messageProps[$this->proptags['responsestatus']] === olResponseOrganized) {
1672
				return true;
1673
			}
1674
		}
1675
1676
		return false;
1677
	}
1678
1679
	/*
1680
	 * Support functions - INTERNAL ONLY
1681
	 ***************************************************************************************************
1682
	 */
1683
1684
	/**
1685
	 * Return the tracking status of a recipient based on the IPM class (passed).
1686
	 *
1687
	 * @param mixed $class
1688
	 */
1689
	public function getTrackStatus($class) {
1690
		$status = olRecipientTrackStatusNone;
1691
1692
		switch ($class) {
1693
			case 'IPM.Schedule.Meeting.Resp.Pos':
1694
				$status = olRecipientTrackStatusAccepted;
1695
				break;
1696
1697
			case 'IPM.Schedule.Meeting.Resp.Tent':
1698
				$status = olRecipientTrackStatusTentative;
1699
				break;
1700
1701
			case 'IPM.Schedule.Meeting.Resp.Neg':
1702
				$status = olRecipientTrackStatusDeclined;
1703
				break;
1704
		}
1705
1706
		return $status;
1707
	}
1708
1709
	/**
1710
	 * Function returns MAPIFolder resource of the folder that currently holds this meeting/meeting request
1711
	 * object.
1712
	 */
1713
	public function openParentFolder() {
1714
		$messageprops = mapi_getprops($this->message, [PR_PARENT_ENTRYID]);
0 ignored issues
show
The constant PR_PARENT_ENTRYID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
The function mapi_getprops was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

1714
		$messageprops = /** @scrutinizer ignore-call */ mapi_getprops($this->message, [PR_PARENT_ENTRYID]);
Loading history...
1715
1716
		return mapi_msgstore_openentry($this->store, $messageprops[PR_PARENT_ENTRYID]);
0 ignored issues
show
The function mapi_msgstore_openentry was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

1716
		return /** @scrutinizer ignore-call */ mapi_msgstore_openentry($this->store, $messageprops[PR_PARENT_ENTRYID]);
Loading history...
1717
	}
1718
1719
	/**
1720
	 * Function will return resource of the default calendar folder of store.
1721
	 *
1722
	 * @param mixed $store {optional} user store whose default calendar should be opened
1723
	 *
1724
	 * @return resource default calendar folder of store
1725
	 */
1726
	public function openDefaultCalendar($store = false) {
1727
		return $this->openDefaultFolder(PR_IPM_APPOINTMENT_ENTRYID, $store);
0 ignored issues
show
The constant PR_IPM_APPOINTMENT_ENTRYID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1728
	}
1729
1730
	/**
1731
	 * Function will return resource of the default outbox folder of store.
1732
	 *
1733
	 * @param mixed $store {optional} user store whose default outbox should be opened
1734
	 *
1735
	 * @return resource default outbox folder of store
1736
	 */
1737
	public function openDefaultOutbox($store = false) {
1738
		return $this->openBaseFolder(PR_IPM_OUTBOX_ENTRYID, $store);
0 ignored issues
show
The constant PR_IPM_OUTBOX_ENTRYID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1739
	}
1740
1741
	/**
1742
	 * Function will return resource of the default wastebasket folder of store.
1743
	 *
1744
	 * @param mixed $store {optional} user store whose default wastebasket should be opened
1745
	 *
1746
	 * @return resource default wastebasket folder of store
1747
	 */
1748
	public function openDefaultWastebasket($store = false) {
1749
		return $this->openBaseFolder(PR_IPM_WASTEBASKET_ENTRYID, $store);
0 ignored issues
show
The constant PR_IPM_WASTEBASKET_ENTRYID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1750
	}
1751
1752
	/**
1753
	 * Function will return resource of the default calendar folder of store.
1754
	 *
1755
	 * @param mixed $store {optional} user store whose default calendar should be opened
1756
	 *
1757
	 * @return bool|string default calendar folder of store
1758
	 */
1759
	public function getDefaultWastebasketEntryID($store = false) {
1760
		return $this->getBaseEntryID(PR_IPM_WASTEBASKET_ENTRYID, $store);
0 ignored issues
show
The constant PR_IPM_WASTEBASKET_ENTRYID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1761
	}
1762
1763
	/**
1764
	 * Function will return resource of the default sent mail folder of store.
1765
	 *
1766
	 * @param mixed $store {optional} user store whose default sent mail should be opened
1767
	 *
1768
	 * @return bool|string default sent mail folder of store
1769
	 */
1770
	public function getDefaultSentmailEntryID($store = false) {
1771
		return $this->getBaseEntryID(PR_IPM_SENTMAIL_ENTRYID, $store);
0 ignored issues
show
The constant PR_IPM_SENTMAIL_ENTRYID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1772
	}
1773
1774
	/**
1775
	 * Function will return entryid of any default folder of store. This method is useful when you want
1776
	 * to get entryid of folder which is stored as properties of inbox folder
1777
	 * (PR_IPM_APPOINTMENT_ENTRYID, PR_IPM_CONTACT_ENTRYID, PR_IPM_DRAFTS_ENTRYID, PR_IPM_JOURNAL_ENTRYID, PR_IPM_NOTE_ENTRYID, PR_IPM_TASK_ENTRYID).
1778
	 *
1779
	 * @param int   $prop  proptag of the folder for which we want to get entryid
1780
	 * @param mixed $store {optional} user store from which we need to get entryid of default folder
1781
	 *
1782
	 * @return bool|string entryid of folder pointed by $prop
1783
	 */
1784
	public function getDefaultFolderEntryID($prop, $store = false) {
1785
		try {
1786
			$inbox = mapi_msgstore_getreceivefolder($store ? $store : $this->store);
0 ignored issues
show
The function mapi_msgstore_getreceivefolder was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

1786
			$inbox = /** @scrutinizer ignore-call */ mapi_msgstore_getreceivefolder($store ? $store : $this->store);
Loading history...
1787
			$inboxprops = mapi_getprops($inbox, [$prop]);
0 ignored issues
show
The function mapi_getprops was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

1787
			$inboxprops = /** @scrutinizer ignore-call */ mapi_getprops($inbox, [$prop]);
Loading history...
1788
			if (isset($inboxprops[$prop])) {
1789
				return $inboxprops[$prop];
1790
			}
1791
		}
1792
		catch (MAPIException $e) {
1793
			// public store doesn't support this method
1794
			if ($e->getCode() == MAPI_E_NO_SUPPORT) {
0 ignored issues
show
The constant MAPI_E_NO_SUPPORT was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1795
				// don't propagate this error to parent handlers, if store doesn't support it
1796
				$e->setHandled();
1797
			}
1798
		}
1799
1800
		return false;
1801
	}
1802
1803
	/**
1804
	 * Function will return resource of any default folder of store.
1805
	 *
1806
	 * @param int   $prop  proptag of the folder that we want to open
1807
	 * @param mixed $store {optional} user store from which we need to open default folder
1808
	 *
1809
	 * @return resource default folder of store
1810
	 */
1811
	public function openDefaultFolder($prop, $store = false) {
1812
		$folder = false;
1813
		$entryid = $this->getDefaultFolderEntryID($prop, $store);
1814
1815
		if ($entryid !== false) {
1816
			$folder = mapi_msgstore_openentry($store ? $store : $this->store, $entryid);
0 ignored issues
show
The function mapi_msgstore_openentry was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

1816
			$folder = /** @scrutinizer ignore-call */ mapi_msgstore_openentry($store ? $store : $this->store, $entryid);
Loading history...
1817
		}
1818
1819
		return $folder;
1820
	}
1821
1822
	/**
1823
	 * Function will return entryid of default folder from store. This method is useful when you want
1824
	 * to get entryid of folder which is stored as store properties
1825
	 * (PR_IPM_FAVORITES_ENTRYID, PR_IPM_OUTBOX_ENTRYID, PR_IPM_SENTMAIL_ENTRYID, PR_IPM_WASTEBASKET_ENTRYID).
1826
	 *
1827
	 * @param int   $prop  proptag of the folder whose entryid we want to get
1828
	 * @param mixed $store {optional} user store from which we need to get entryid of default folder
1829
	 *
1830
	 * @return bool|string entryid of default folder from store
1831
	 */
1832
	public function getBaseEntryID($prop, $store = false) {
1833
		$storeprops = mapi_getprops($store ? $store : $this->store, [$prop]);
0 ignored issues
show
The function mapi_getprops was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

1833
		$storeprops = /** @scrutinizer ignore-call */ mapi_getprops($store ? $store : $this->store, [$prop]);
Loading history...
1834
		if (!isset($storeprops[$prop])) {
1835
			return false;
1836
		}
1837
1838
		return $storeprops[$prop];
1839
	}
1840
1841
	/**
1842
	 * Function will return resource of any default folder of store.
1843
	 *
1844
	 * @param int   $prop  proptag of the folder that we want to open
1845
	 * @param mixed $store {optional} user store from which we need to open default folder
1846
	 *
1847
	 * @return resource default folder of store
1848
	 */
1849
	public function openBaseFolder($prop, $store = false) {
1850
		$folder = false;
1851
		$entryid = $this->getBaseEntryID($prop, $store);
1852
1853
		if ($entryid !== false) {
1854
			$folder = mapi_msgstore_openentry($store ? $store : $this->store, $entryid);
0 ignored issues
show
The function mapi_msgstore_openentry was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

1854
			$folder = /** @scrutinizer ignore-call */ mapi_msgstore_openentry($store ? $store : $this->store, $entryid);
Loading history...
1855
		}
1856
1857
		return $folder;
1858
	}
1859
1860
	/**
1861
	 * Function checks whether user has access over the specified folder or not.
1862
	 *
1863
	 * @param string $entryid entryid The entryid of the folder to check
1864
	 * @param mixed  $store   (optional) store from which folder should be opened
1865
	 *
1866
	 * @return bool true if user has an access over the folder, false if not
1867
	 */
1868
	public function checkFolderWriteAccess($entryid, $store = false) {
1869
		$accessToFolder = false;
1870
1871
		if (!empty($entryid)) {
1872
			if ($store === false) {
1873
				$store = $this->store;
1874
			}
1875
1876
			try {
1877
				$folder = mapi_msgstore_openentry($store, $entryid);
0 ignored issues
show
The function mapi_msgstore_openentry was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

1877
				$folder = /** @scrutinizer ignore-call */ mapi_msgstore_openentry($store, $entryid);
Loading history...
1878
				$folderProps = mapi_getprops($folder, [PR_ACCESS]);
0 ignored issues
show
The constant PR_ACCESS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
The function mapi_getprops was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

1878
				$folderProps = /** @scrutinizer ignore-call */ mapi_getprops($folder, [PR_ACCESS]);
Loading history...
1879
				if (($folderProps[PR_ACCESS] & MAPI_ACCESS_CREATE_CONTENTS) === MAPI_ACCESS_CREATE_CONTENTS) {
1880
					$accessToFolder = true;
1881
				}
1882
			}
1883
			catch (MAPIException $e) {
1884
				// we don't have rights to open folder, so return false
1885
				if ($e->getCode() == MAPI_E_NO_ACCESS) {
0 ignored issues
show
The constant MAPI_E_NO_ACCESS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1886
					return $accessToFolder;
1887
				}
1888
1889
				// rethrow other errors
1890
				throw $e;
1891
			}
1892
		}
1893
1894
		return $accessToFolder;
1895
	}
1896
1897
	/**
1898
	 * Function checks whether user has access over the specified folder or not.
1899
	 *
1900
	 * @param mixed $store
1901
	 *
1902
	 * @return bool true if user has an access over the folder, false if not
1903
	 */
1904
	public function checkCalendarWriteAccess($store = false) {
1905
		if ($store === false) {
1906
			// If this meeting request is received by a delegate then open delegator's store.
1907
			$messageProps = mapi_getprops($this->message, [PR_RCVD_REPRESENTING_ENTRYID]);
0 ignored issues
show
The function mapi_getprops was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

1907
			$messageProps = /** @scrutinizer ignore-call */ mapi_getprops($this->message, [PR_RCVD_REPRESENTING_ENTRYID]);
Loading history...
The constant PR_RCVD_REPRESENTING_ENTRYID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1908
			if (isset($messageProps[PR_RCVD_REPRESENTING_ENTRYID])) {
1909
				$delegatorStore = $this->getDelegatorStore($messageProps[PR_RCVD_REPRESENTING_ENTRYID]);
1910
1911
				$store = $delegatorStore['store'];
1912
			}
1913
			else {
1914
				$store = $this->store;
1915
			}
1916
		}
1917
1918
		// If the store is a public folder, the calendar folder is the PARENT_ENTRYID of the calendar item
1919
		$provider = mapi_getprops($store, [PR_MDB_PROVIDER]);
0 ignored issues
show
The constant PR_MDB_PROVIDER was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1920
		if (isset($provider[PR_MDB_PROVIDER]) && $provider[PR_MDB_PROVIDER] === ZARAFA_STORE_PUBLIC_GUID) {
1921
			$entryid = mapi_getprops($this->message, [PR_PARENT_ENTRYID]);
0 ignored issues
show
The constant PR_PARENT_ENTRYID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1922
			$entryid = $entryid[PR_PARENT_ENTRYID];
1923
		}
1924
		else {
1925
			$entryid = $this->getDefaultFolderEntryID(PR_IPM_APPOINTMENT_ENTRYID, $store);
0 ignored issues
show
The constant PR_IPM_APPOINTMENT_ENTRYID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1926
			if ($entryid === false) {
1927
				$entryid = $this->getBaseEntryID(PR_IPM_APPOINTMENT_ENTRYID, $store);
1928
			}
1929
1930
			if ($entryid === false) {
1931
				return false;
1932
			}
1933
		}
1934
1935
		return $this->checkFolderWriteAccess($entryid, $store);
1936
	}
1937
1938
	/**
1939
	 * Function will resolve the user and open its store.
1940
	 *
1941
	 * @param string $ownerentryid the entryid of the user
1942
	 *
1943
	 * @return resource store of the user
1944
	 */
1945
	public function openCustomUserStore($ownerentryid) {
1946
		$ab = mapi_openaddressbook($this->session);
0 ignored issues
show
The function mapi_openaddressbook was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

1946
		$ab = /** @scrutinizer ignore-call */ mapi_openaddressbook($this->session);
Loading history...
1947
1948
		try {
1949
			$mailuser = mapi_ab_openentry($ab, $ownerentryid);
0 ignored issues
show
The function mapi_ab_openentry was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

1949
			$mailuser = /** @scrutinizer ignore-call */ mapi_ab_openentry($ab, $ownerentryid);
Loading history...
1950
		}
1951
		catch (MAPIException $e) {
1952
			return;
1953
		}
1954
1955
		$mailuserprops = mapi_getprops($mailuser, [PR_EMAIL_ADDRESS]);
0 ignored issues
show
The constant PR_EMAIL_ADDRESS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
The function mapi_getprops was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

1955
		$mailuserprops = /** @scrutinizer ignore-call */ mapi_getprops($mailuser, [PR_EMAIL_ADDRESS]);
Loading history...
1956
		$storeid = mapi_msgstore_createentryid($this->store, $mailuserprops[PR_EMAIL_ADDRESS]);
0 ignored issues
show
The function mapi_msgstore_createentryid was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

1956
		$storeid = /** @scrutinizer ignore-call */ mapi_msgstore_createentryid($this->store, $mailuserprops[PR_EMAIL_ADDRESS]);
Loading history...
1957
1958
		return mapi_openmsgstore($this->session, $storeid);
0 ignored issues
show
The function mapi_openmsgstore was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

1958
		return /** @scrutinizer ignore-call */ mapi_openmsgstore($this->session, $storeid);
Loading history...
1959
	}
1960
1961
	/**
1962
	 * Function which sends response to organizer when attendee accepts, declines or proposes new time to a received meeting request.
1963
	 *
1964
	 * @param int   $status              response status of attendee
1965
	 * @param array $proposeNewTimeProps properties of attendee's proposal
1966
	 * @param mixed $body
1967
	 * @param mixed $store
1968
	 * @param mixed $basedate            date of occurrence which attendee has responded
1969
	 * @param mixed $calFolder
1970
	 */
1971
	public function createResponse($status, $proposeNewTimeProps, $body, $store, $basedate, $calFolder): void {
1972
		$messageprops = mapi_getprops($this->message, [
0 ignored issues
show
The function mapi_getprops was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

1972
		$messageprops = /** @scrutinizer ignore-call */ mapi_getprops($this->message, [
Loading history...
1973
			PR_SENT_REPRESENTING_ENTRYID,
0 ignored issues
show
The constant PR_SENT_REPRESENTING_ENTRYID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1974
			PR_SENT_REPRESENTING_EMAIL_ADDRESS,
0 ignored issues
show
The constant PR_SENT_REPRESENTING_EMAIL_ADDRESS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1975
			PR_SENT_REPRESENTING_ADDRTYPE,
0 ignored issues
show
The constant PR_SENT_REPRESENTING_ADDRTYPE was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1976
			PR_SENT_REPRESENTING_NAME,
0 ignored issues
show
The constant PR_SENT_REPRESENTING_NAME was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1977
			PR_SENT_REPRESENTING_SEARCH_KEY,
0 ignored issues
show
The constant PR_SENT_REPRESENTING_SEARCH_KEY was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1978
			$this->proptags['goid'],
1979
			$this->proptags['goid2'],
1980
			$this->proptags['location'],
1981
			$this->proptags['startdate'],
1982
			$this->proptags['duedate'],
1983
			$this->proptags['recurring'],
1984
			$this->proptags['recurring_pattern'],
1985
			$this->proptags['recurrence_data'],
1986
			$this->proptags['timezone_data'],
1987
			$this->proptags['timezone'],
1988
			$this->proptags['updatecounter'],
1989
			PR_SUBJECT,
0 ignored issues
show
The constant PR_SUBJECT was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1990
			PR_MESSAGE_CLASS,
0 ignored issues
show
The constant PR_MESSAGE_CLASS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1991
			PR_OWNER_APPT_ID,
0 ignored issues
show
The constant PR_OWNER_APPT_ID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1992
			$this->proptags['is_exception'],
1993
		]);
1994
1995
		$props = [];
1996
1997
		if ($basedate !== false && !$this->isMeetingRequest($messageprops[PR_MESSAGE_CLASS])) {
1998
			// we are creating response from a recurring calendar item object
1999
			// We found basedate,so opened occurrence and get properties.
2000
			$recurr = new Recurrence($store, $this->message);
2001
			$exception = $recurr->getExceptionAttachment($basedate);
2002
2003
			if ($exception) {
2004
				// Exception found, Now retrieve properties
2005
				$imessage = mapi_attach_openobj($exception, 0);
0 ignored issues
show
The function mapi_attach_openobj was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

2005
				$imessage = /** @scrutinizer ignore-call */ mapi_attach_openobj($exception, 0);
Loading history...
2006
				$imsgprops = mapi_getprops($imessage);
2007
2008
				// If location is provided, copy it to the response
2009
				if (isset($imsgprops[$this->proptags['location']])) {
2010
					$messageprops[$this->proptags['location']] = $imsgprops[$this->proptags['location']];
2011
				}
2012
2013
				// Update $messageprops with timings of occurrence
2014
				$messageprops[$this->proptags['startdate']] = $imsgprops[$this->proptags['startdate']];
2015
				$messageprops[$this->proptags['duedate']] = $imsgprops[$this->proptags['duedate']];
2016
2017
				// Meeting related properties
2018
				$props[$this->proptags['meetingstatus']] = $imsgprops[$this->proptags['meetingstatus']];
2019
				$props[$this->proptags['responsestatus']] = $imsgprops[$this->proptags['responsestatus']];
2020
				$props[PR_SUBJECT] = $imsgprops[PR_SUBJECT];
2021
			}
2022
			else {
2023
				// Exceptions is deleted.
2024
				// Update $messageprops with timings of occurrence
2025
				$messageprops[$this->proptags['startdate']] = $recurr->getOccurrenceStart($basedate);
2026
				$messageprops[$this->proptags['duedate']] = $recurr->getOccurrenceEnd($basedate);
2027
2028
				$props[$this->proptags['meetingstatus']] = olNonMeeting;
2029
				$props[$this->proptags['responsestatus']] = olResponseNone;
2030
			}
2031
2032
			$props[$this->proptags['recurring']] = false;
2033
			$props[$this->proptags['is_exception']] = true;
2034
		}
2035
		else {
2036
			// we are creating a response from meeting request mail (it could be recurring or non-recurring)
2037
			// Send all recurrence info in response, if this is a recurrence meeting.
2038
			$isRecurring = isset($messageprops[$this->proptags['recurring']]) && $messageprops[$this->proptags['recurring']];
2039
			$isException = isset($messageprops[$this->proptags['is_exception']]) && $messageprops[$this->proptags['is_exception']];
2040
			if ($isRecurring || $isException) {
2041
				if ($isRecurring) {
2042
					$props[$this->proptags['recurring']] = $messageprops[$this->proptags['recurring']];
2043
				}
2044
				if ($isException) {
2045
					$props[$this->proptags['is_exception']] = $messageprops[$this->proptags['is_exception']];
2046
				}
2047
				$calendaritems = $this->findCalendarItems($messageprops[$this->proptags['goid2']], $calFolder);
2048
2049
				$calendaritem = mapi_msgstore_openentry($store, $calendaritems[0]);
0 ignored issues
show
The function mapi_msgstore_openentry was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

2049
				$calendaritem = /** @scrutinizer ignore-call */ mapi_msgstore_openentry($store, $calendaritems[0]);
Loading history...
2050
				$recurr = new Recurrence($store, $calendaritem);
2051
			}
2052
		}
2053
2054
		// we are sending a response for recurring meeting request (or exception), so set some required properties
2055
		if (isset($recurr) && $recurr) {
2056
			if (!empty($messageprops[$this->proptags['recurring_pattern']])) {
2057
				$props[$this->proptags['recurring_pattern']] = $messageprops[$this->proptags['recurring_pattern']];
2058
			}
2059
2060
			if (!empty($messageprops[$this->proptags['recurrence_data']])) {
2061
				$props[$this->proptags['recurrence_data']] = $messageprops[$this->proptags['recurrence_data']];
2062
			}
2063
2064
			$props[$this->proptags['timezone_data']] = $messageprops[$this->proptags['timezone_data']];
2065
			$props[$this->proptags['timezone']] = $messageprops[$this->proptags['timezone']];
2066
2067
			$this->generateRecurDates($recurr, $messageprops, $props);
2068
		}
2069
2070
		// Create a response message
2071
		$recip = [];
2072
		$recip[PR_ENTRYID] = $messageprops[PR_SENT_REPRESENTING_ENTRYID];
2073
		$recip[PR_EMAIL_ADDRESS] = $messageprops[PR_SENT_REPRESENTING_EMAIL_ADDRESS];
0 ignored issues
show
The constant PR_EMAIL_ADDRESS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
2074
		$recip[PR_ADDRTYPE] = $messageprops[PR_SENT_REPRESENTING_ADDRTYPE];
0 ignored issues
show
The constant PR_ADDRTYPE was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
2075
		$recip[PR_DISPLAY_NAME] = $messageprops[PR_SENT_REPRESENTING_NAME];
0 ignored issues
show
The constant PR_DISPLAY_NAME was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
2076
		$recip[PR_RECIPIENT_TYPE] = MAPI_TO;
0 ignored issues
show
The constant PR_RECIPIENT_TYPE was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
2077
		$recip[PR_SEARCH_KEY] = $messageprops[PR_SENT_REPRESENTING_SEARCH_KEY];
0 ignored issues
show
The constant PR_SEARCH_KEY was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
2078
2079
		$subjectprefix = '';
2080
2081
		switch ($status) {
2082
			case olResponseAccepted:
2083
				$classpostfix = 'Pos';
2084
				$subjectprefix = dgettext('zarafa', 'Accepted');
2085
				break;
2086
2087
			case olResponseDeclined:
2088
				$classpostfix = 'Neg';
2089
				$subjectprefix = dgettext('zarafa', 'Declined');
2090
				break;
2091
2092
			case olResponseTentative:
2093
				$classpostfix = 'Tent';
2094
				$subjectprefix = dgettext('zarafa', 'Tentatively accepted');
2095
				break;
2096
		}
2097
2098
		if (!empty($proposeNewTimeProps)) {
2099
			// if attendee has proposed new time then change subject prefix
2100
			$subjectprefix = dgettext('zarafa', 'New Time Proposed');
2101
		}
2102
2103
		$props[PR_SUBJECT] = $subjectprefix . ': ' . $messageprops[PR_SUBJECT];
2104
2105
		$props[PR_MESSAGE_CLASS] = 'IPM.Schedule.Meeting.Resp.' . $classpostfix;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $classpostfix does not seem to be defined for all execution paths leading up to this point.
Loading history...
2106
		if (isset($messageprops[PR_OWNER_APPT_ID])) {
2107
			$props[PR_OWNER_APPT_ID] = $messageprops[PR_OWNER_APPT_ID];
2108
		}
2109
2110
		// Set GlobalId AND CleanGlobalId, if exception then also set basedate into GlobalId(0x3).
2111
		$props[$this->proptags['goid']] = $this->setBasedateInGlobalID($messageprops[$this->proptags['goid2']], $basedate);
2112
		$props[$this->proptags['goid2']] = $messageprops[$this->proptags['goid2']];
2113
		$props[$this->proptags['updatecounter']] = isset($messageprops[$this->proptags['updatecounter']]) ? $messageprops[$this->proptags['updatecounter']] : 0;
2114
2115
		if (!empty($proposeNewTimeProps)) {
2116
			// merge proposal properties to message properties which will be sent to organizer
2117
			$props = $proposeNewTimeProps + $props;
2118
		}
2119
2120
		// Set body message in Appointment
2121
		if (isset($body)) {
2122
			$props[PR_BODY] = $this->getMeetingTimeInfo() ? $this->getMeetingTimeInfo() : $body;
0 ignored issues
show
The constant PR_BODY was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
2123
		}
2124
2125
		// PR_START_DATE/PR_END_DATE is used in the UI in Outlook on the response message
2126
		$props[PR_START_DATE] = $messageprops[$this->proptags['startdate']];
0 ignored issues
show
The constant PR_START_DATE was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
2127
		$props[PR_END_DATE] = $messageprops[$this->proptags['duedate']];
0 ignored issues
show
The constant PR_END_DATE was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
2128
2129
		// Set startdate and duedate in response mail.
2130
		$props[$this->proptags['startdate']] = $messageprops[$this->proptags['startdate']];
2131
		$props[$this->proptags['duedate']] = $messageprops[$this->proptags['duedate']];
2132
2133
		// responselocation is used in the UI in Outlook on the response message
2134
		if (isset($messageprops[$this->proptags['location']])) {
2135
			$props[$this->proptags['responselocation']] = $messageprops[$this->proptags['location']];
2136
			$props[$this->proptags['location']] = $messageprops[$this->proptags['location']];
2137
		}
2138
2139
		$message = $this->createOutgoingMessage($store);
2140
2141
		mapi_setprops($message, $props);
0 ignored issues
show
The function mapi_setprops was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

2141
		/** @scrutinizer ignore-call */ 
2142
  mapi_setprops($message, $props);
Loading history...
2142
		mapi_message_modifyrecipients($message, MODRECIP_ADD, [$recip]);
0 ignored issues
show
The function mapi_message_modifyrecipients was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

2142
		/** @scrutinizer ignore-call */ 
2143
  mapi_message_modifyrecipients($message, MODRECIP_ADD, [$recip]);
Loading history...
2143
		mapi_savechanges($message);
0 ignored issues
show
The function mapi_savechanges was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

2143
		/** @scrutinizer ignore-call */ 
2144
  mapi_savechanges($message);
Loading history...
2144
		mapi_message_submitmessage($message);
0 ignored issues
show
The function mapi_message_submitmessage was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

2144
		/** @scrutinizer ignore-call */ 
2145
  mapi_message_submitmessage($message);
Loading history...
2145
	}
2146
2147
	/**
2148
	 * Function which finds items in calendar based on globalId and cleanGlobalId.
2149
	 *
2150
	 * @param string $goid             GlobalID(0x3) of item
2151
	 * @param mixed  $calendar         MAPI_folder of user (optional)
2152
	 * @param bool   $useCleanGlobalId if true then search should be performed on cleanGlobalId(0x23) else globalId(0x3)
2153
	 *
2154
	 * @return mixed
2155
	 */
2156
	public function findCalendarItems($goid, $calendar = false, $useCleanGlobalId = false) {
2157
		if ($calendar === false) {
2158
			// Open the Calendar
2159
			$calendar = $this->openDefaultCalendar();
2160
		}
2161
2162
		// Find the item by restricting all items to the correct ID
2163
		$restrict = [
2164
			RES_PROPERTY,
2165
			[
2166
				RELOP => RELOP_EQ,
2167
				ULPROPTAG => ($useCleanGlobalId === true ? $this->proptags['goid2'] : $this->proptags['goid']),
2168
				VALUE => $goid,
2169
			],
2170
		];
2171
2172
		$calendarcontents = mapi_folder_getcontentstable($calendar);
0 ignored issues
show
The function mapi_folder_getcontentstable was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

2172
		$calendarcontents = /** @scrutinizer ignore-call */ mapi_folder_getcontentstable($calendar);
Loading history...
2173
2174
		$rows = mapi_table_queryallrows($calendarcontents, [PR_ENTRYID], $restrict);
0 ignored issues
show
The function mapi_table_queryallrows was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

2174
		$rows = /** @scrutinizer ignore-call */ mapi_table_queryallrows($calendarcontents, [PR_ENTRYID], $restrict);
Loading history...
2175
2176
		if (empty($rows)) {
2177
			return;
2178
		}
2179
2180
		$calendaritems = [];
2181
2182
		// In principle, there should only be one row, but we'll handle them all just in case
2183
		foreach ($rows as $row) {
2184
			$calendaritems[] = $row[PR_ENTRYID];
2185
		}
2186
2187
		return $calendaritems;
2188
	}
2189
2190
	// Returns TRUE if both entryid's are equal. Equality is defined by both entryid's pointing at the
2191
	// same SMTP address when converted to SMTP
2192
	public function compareABEntryIDs($entryid1, $entryid2): bool {
2193
		// If the session was not passed, just do a 'normal' compare.
2194
		if (!$this->session) {
2195
			return $entryid1 == $entryid2;
2196
		}
2197
2198
		$smtp1 = $this->getSMTPAddress($entryid1);
2199
		$smtp2 = $this->getSMTPAddress($entryid2);
2200
2201
		if ($smtp1 == $smtp2) {
2202
			return true;
2203
		}
2204
2205
		return false;
2206
	}
2207
2208
	// Gets the SMTP address of the passed addressbook entryid
2209
	public function getSMTPAddress($entryid) {
2210
		if (!$this->session) {
2211
			return false;
2212
		}
2213
2214
		try {
2215
			$ab = mapi_openaddressbook($this->session);
0 ignored issues
show
The function mapi_openaddressbook was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

2215
			$ab = /** @scrutinizer ignore-call */ mapi_openaddressbook($this->session);
Loading history...
2216
			$abitem = mapi_ab_openentry($ab, $entryid);
0 ignored issues
show
The function mapi_ab_openentry was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

2216
			$abitem = /** @scrutinizer ignore-call */ mapi_ab_openentry($ab, $entryid);
Loading history...
2217
2218
			if (!$abitem) {
2219
				return '';
2220
			}
2221
		}
2222
		catch (MAPIException $e) {
2223
			return '';
2224
		}
2225
2226
		$props = mapi_getprops($abitem, [PR_ADDRTYPE, PR_EMAIL_ADDRESS, PR_SMTP_ADDRESS]);
0 ignored issues
show
The constant PR_ADDRTYPE was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
The constant PR_SMTP_ADDRESS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
The function mapi_getprops was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

2226
		$props = /** @scrutinizer ignore-call */ mapi_getprops($abitem, [PR_ADDRTYPE, PR_EMAIL_ADDRESS, PR_SMTP_ADDRESS]);
Loading history...
The constant PR_EMAIL_ADDRESS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
2227
2228
		if ($props[PR_ADDRTYPE] == 'SMTP') {
2229
			return $props[PR_EMAIL_ADDRESS];
2230
		}
2231
2232
		return $props[PR_SMTP_ADDRESS];
2233
	}
2234
2235
	/**
2236
	 * Gets the properties associated with the owner of the passed store:
2237
	 * PR_DISPLAY_NAME, PR_EMAIL_ADDRESS, PR_ADDRTYPE, PR_ENTRYID, PR_SEARCH_KEY.
2238
	 *
2239
	 * @param mixed $store                  message store
2240
	 * @param bool  $fallbackToLoggedInUser If true then return properties of logged in user instead of mailbox owner.
2241
	 *                                      Not used when passed store is public store.
2242
	 *                                      For public store we are always returning logged in user's info.
2243
	 *
2244
	 * @return array|false properties of logged in user in an array in sequence of display_name, email address, address type, entryid and search key
2245
	 *
2246
	 * @psalm-return false|list{mixed, mixed, mixed, mixed, mixed}
2247
	 */
2248
	public function getOwnerAddress($store, $fallbackToLoggedInUser = true) {
2249
		if (!$this->session) {
2250
			return false;
2251
		}
2252
2253
		$storeProps = mapi_getprops($store, [PR_MAILBOX_OWNER_ENTRYID, PR_USER_ENTRYID]);
0 ignored issues
show
The constant PR_USER_ENTRYID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
The constant PR_MAILBOX_OWNER_ENTRYID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
The function mapi_getprops was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

2253
		$storeProps = /** @scrutinizer ignore-call */ mapi_getprops($store, [PR_MAILBOX_OWNER_ENTRYID, PR_USER_ENTRYID]);
Loading history...
2254
2255
		$ownerEntryId = false;
2256
		if (isset($storeProps[PR_USER_ENTRYID]) && $storeProps[PR_USER_ENTRYID]) {
2257
			$ownerEntryId = $storeProps[PR_USER_ENTRYID];
2258
		}
2259
2260
		if (isset($storeProps[PR_MAILBOX_OWNER_ENTRYID]) && $storeProps[PR_MAILBOX_OWNER_ENTRYID] && !$fallbackToLoggedInUser) {
2261
			$ownerEntryId = $storeProps[PR_MAILBOX_OWNER_ENTRYID];
2262
		}
2263
2264
		if ($ownerEntryId) {
2265
			$ab = mapi_openaddressbook($this->session);
0 ignored issues
show
The function mapi_openaddressbook was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

2265
			$ab = /** @scrutinizer ignore-call */ mapi_openaddressbook($this->session);
Loading history...
2266
2267
			$zarafaUser = mapi_ab_openentry($ab, $ownerEntryId);
0 ignored issues
show
The function mapi_ab_openentry was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

2267
			$zarafaUser = /** @scrutinizer ignore-call */ mapi_ab_openentry($ab, $ownerEntryId);
Loading history...
2268
			if (!$zarafaUser) {
2269
				return false;
2270
			}
2271
2272
			$ownerProps = mapi_getprops($zarafaUser, [PR_ADDRTYPE, PR_DISPLAY_NAME, PR_EMAIL_ADDRESS, PR_SEARCH_KEY]);
0 ignored issues
show
The constant PR_SEARCH_KEY was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
The constant PR_DISPLAY_NAME was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
The constant PR_ADDRTYPE was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
The constant PR_EMAIL_ADDRESS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
2273
2274
			$addrType = $ownerProps[PR_ADDRTYPE];
2275
			$name = $ownerProps[PR_DISPLAY_NAME];
2276
			$emailAddr = $ownerProps[PR_EMAIL_ADDRESS];
2277
			$searchKey = $ownerProps[PR_SEARCH_KEY];
2278
			$entryId = $ownerEntryId;
2279
2280
			return [$name, $emailAddr, $addrType, $entryId, $searchKey];
2281
		}
2282
2283
		return false;
2284
	}
2285
2286
	// Opens this session's default message store
2287
	public function openDefaultStore() {
2288
		$storestable = mapi_getmsgstorestable($this->session);
0 ignored issues
show
The function mapi_getmsgstorestable was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

2288
		$storestable = /** @scrutinizer ignore-call */ mapi_getmsgstorestable($this->session);
Loading history...
2289
		$rows = mapi_table_queryallrows($storestable, [PR_ENTRYID, PR_DEFAULT_STORE]);
0 ignored issues
show
The constant PR_DEFAULT_STORE was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
The function mapi_table_queryallrows was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

2289
		$rows = /** @scrutinizer ignore-call */ mapi_table_queryallrows($storestable, [PR_ENTRYID, PR_DEFAULT_STORE]);
Loading history...
2290
2291
		foreach ($rows as $row) {
2292
			if (isset($row[PR_DEFAULT_STORE]) && $row[PR_DEFAULT_STORE]) {
2293
				$entryid = $row[PR_ENTRYID];
2294
				break;
2295
			}
2296
		}
2297
2298
		if (!$entryid) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $entryid does not seem to be defined for all execution paths leading up to this point.
Loading history...
2299
			return false;
2300
		}
2301
2302
		return mapi_openmsgstore($this->session, $entryid);
0 ignored issues
show
The function mapi_openmsgstore was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

2302
		return /** @scrutinizer ignore-call */ mapi_openmsgstore($this->session, $entryid);
Loading history...
2303
	}
2304
2305
	/**
2306
	 * Function which adds organizer to recipient list which is passed.
2307
	 * This function also checks if it has organizer.
2308
	 *
2309
	 * @param array $messageProps message properties
2310
	 * @param array $recipients   recipients list of message
2311
	 * @param bool  $isException  true if we are processing recipient of exception
2312
	 */
2313
	public function addOrganizer($messageProps, &$recipients, $isException = false): void {
2314
		$hasOrganizer = false;
2315
		// Check if meeting already has an organizer.
2316
		foreach ($recipients as $key => $recipient) {
2317
			if (isset($recipient[PR_RECIPIENT_FLAGS]) && $recipient[PR_RECIPIENT_FLAGS] == (recipSendable | recipOrganizer)) {
0 ignored issues
show
The constant PR_RECIPIENT_FLAGS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
2318
				$hasOrganizer = true;
2319
			}
2320
			elseif ($isException && !isset($recipient[PR_RECIPIENT_FLAGS])) {
2321
				// Recipients for an occurrence
2322
				$recipients[$key][PR_RECIPIENT_FLAGS] = recipSendable | recipExceptionalResponse;
2323
			}
2324
		}
2325
2326
		if (!$hasOrganizer) {
2327
			// Create organizer.
2328
			$organizer = [];
2329
			$organizer[PR_ENTRYID] = $messageProps[PR_SENT_REPRESENTING_ENTRYID];
0 ignored issues
show
The constant PR_SENT_REPRESENTING_ENTRYID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
2330
			$organizer[PR_DISPLAY_NAME] = $messageProps[PR_SENT_REPRESENTING_NAME];
0 ignored issues
show
The constant PR_DISPLAY_NAME was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
The constant PR_SENT_REPRESENTING_NAME was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
2331
			$organizer[PR_EMAIL_ADDRESS] = $messageProps[PR_SENT_REPRESENTING_EMAIL_ADDRESS];
0 ignored issues
show
The constant PR_EMAIL_ADDRESS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
The constant PR_SENT_REPRESENTING_EMAIL_ADDRESS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
2332
			$organizer[PR_RECIPIENT_TYPE] = MAPI_TO;
0 ignored issues
show
The constant PR_RECIPIENT_TYPE was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
2333
			$organizer[PR_RECIPIENT_DISPLAY_NAME] = $messageProps[PR_SENT_REPRESENTING_NAME];
0 ignored issues
show
The constant PR_RECIPIENT_DISPLAY_NAME was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
2334
			$organizer[PR_ADDRTYPE] = empty($messageProps[PR_SENT_REPRESENTING_ADDRTYPE]) ? 'SMTP' : $messageProps[PR_SENT_REPRESENTING_ADDRTYPE];
0 ignored issues
show
The constant PR_ADDRTYPE was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
The constant PR_SENT_REPRESENTING_ADDRTYPE was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
2335
			$organizer[PR_RECIPIENT_TRACKSTATUS] = olRecipientTrackStatusNone;
0 ignored issues
show
The constant PR_RECIPIENT_TRACKSTATUS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
2336
			$organizer[PR_RECIPIENT_FLAGS] = recipSendable | recipOrganizer;
2337
			$organizer[PR_SEARCH_KEY] = $messageProps[PR_SENT_REPRESENTING_SEARCH_KEY];
0 ignored issues
show
The constant PR_SENT_REPRESENTING_SEARCH_KEY was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
The constant PR_SEARCH_KEY was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
2338
2339
			// Add organizer to recipients list.
2340
			array_unshift($recipients, $organizer);
2341
		}
2342
	}
2343
2344
	/**
2345
	 * Function which removes an exception/occurrence from recurrencing meeting
2346
	 * when a meeting cancellation of an occurrence is processed.
2347
	 *
2348
	 * @param mixed    $basedate basedate of an occurrence
2349
	 * @param mixed    $message  recurring item from which occurrence has to be deleted
2350
	 * @param resource $store    MAPI_MSG_Store which contains the item
2351
	 */
2352
	public function doRemoveExceptionFromCalendar($basedate, $message, $store): void {
2353
		$recurr = new Recurrence($store, $message);
2354
		$recurr->createException([], $basedate, true);
2355
		mapi_savechanges($message);
0 ignored issues
show
The function mapi_savechanges was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

2355
		/** @scrutinizer ignore-call */ 
2356
  mapi_savechanges($message);
Loading history...
2356
	}
2357
2358
	/**
2359
	 * Function which returns basedate of an changed occurrence from globalID of meeting request.
2360
	 *
2361
	 * @param string $goid globalID
2362
	 *
2363
	 * @return false|int true if basedate is found else false it not found
2364
	 */
2365
	public function getBasedateFromGlobalID($goid) {
2366
		$hexguid = bin2hex($goid);
2367
		$hexbase = substr($hexguid, 32, 8);
2368
		$day = (int) hexdec(substr($hexbase, 6, 2));
2369
		$month = (int) hexdec(substr($hexbase, 4, 2));
2370
		$year = (int) hexdec(substr($hexbase, 0, 4));
2371
2372
		if ($day && $month && $year) {
2373
			return gmmktime(0, 0, 0, $month, $day, $year);
2374
		}
2375
2376
		return false;
2377
	}
2378
2379
	/**
2380
	 * Function which sets basedate in globalID of changed occurrence which is to be sent.
2381
	 *
2382
	 * @param string $goid     globalID
2383
	 * @param mixed  $basedate of changed occurrence
2384
	 *
2385
	 * @return false|string globalID with basedate in it
2386
	 */
2387
	public function setBasedateInGlobalID($goid, $basedate = false) {
2388
		$hexguid = bin2hex($goid);
2389
		$year = $basedate ? sprintf('%04s', dechex((int) gmdate('Y', $basedate))) : '0000';
2390
		$month = $basedate ? sprintf('%02s', dechex((int) gmdate('m', $basedate))) : '00';
2391
		$day = $basedate ? sprintf('%02s', dechex((int) gmdate('d', $basedate))) : '00';
2392
2393
		return hex2bin(strtoupper(substr($hexguid, 0, 32) . $year . $month . $day . substr($hexguid, 40)));
2394
	}
2395
2396
	/**
2397
	 * Function which replaces attachments with copy_from in copy_to.
2398
	 *
2399
	 * @param mixed $copyFrom       MAPI_message from which attachments are to be copied
2400
	 * @param mixed $copyTo         MAPI_message to which attachment are to be copied
2401
	 * @param bool  $copyExceptions if true then all exceptions should also be sent as attachments
2402
	 */
2403
	public function replaceAttachments($copyFrom, $copyTo, $copyExceptions = true): void {
2404
		/* remove all old attachments */
2405
		$attachmentTableTo = mapi_message_getattachmenttable($copyTo);
0 ignored issues
show
The function mapi_message_getattachmenttable was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

2405
		$attachmentTableTo = /** @scrutinizer ignore-call */ mapi_message_getattachmenttable($copyTo);
Loading history...
2406
		if ($attachmentTableTo) {
2407
			$attachments = mapi_table_queryallrows($attachmentTableTo, [PR_ATTACH_NUM, PR_ATTACH_METHOD, PR_EXCEPTION_STARTTIME]);
0 ignored issues
show
The constant PR_ATTACH_NUM was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
The function mapi_table_queryallrows was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

2407
			$attachments = /** @scrutinizer ignore-call */ mapi_table_queryallrows($attachmentTableTo, [PR_ATTACH_NUM, PR_ATTACH_METHOD, PR_EXCEPTION_STARTTIME]);
Loading history...
The constant PR_EXCEPTION_STARTTIME was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
The constant PR_ATTACH_METHOD was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
2408
2409
			foreach ($attachments as $attachProps) {
2410
				/* remove exceptions too? */
2411
				if (!$copyExceptions && $attachProps[PR_ATTACH_METHOD] == ATTACH_EMBEDDED_MSG && isset($attachProps[PR_EXCEPTION_STARTTIME])) {
2412
					continue;
2413
				}
2414
				mapi_message_deleteattach($copyTo, $attachProps[PR_ATTACH_NUM]);
0 ignored issues
show
The function mapi_message_deleteattach was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

2414
				/** @scrutinizer ignore-call */ 
2415
    mapi_message_deleteattach($copyTo, $attachProps[PR_ATTACH_NUM]);
Loading history...
2415
			}
2416
		}
2417
2418
		/* copy new attachments */
2419
		$attachmentTableFrom = mapi_message_getattachmenttable($copyFrom);
2420
		if ($attachmentTableFrom) {
2421
			$attachments = mapi_table_queryallrows($attachmentTableFrom, [PR_ATTACH_NUM, PR_ATTACH_METHOD, PR_EXCEPTION_STARTTIME]);
2422
2423
			foreach ($attachments as $attachProps) {
2424
				if (!$copyExceptions && $attachProps[PR_ATTACH_METHOD] == ATTACH_EMBEDDED_MSG && isset($attachProps[PR_EXCEPTION_STARTTIME])) {
2425
					continue;
2426
				}
2427
2428
				$attachOld = mapi_message_openattach($copyFrom, (int) $attachProps[PR_ATTACH_NUM]);
0 ignored issues
show
The function mapi_message_openattach was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

2428
				$attachOld = /** @scrutinizer ignore-call */ mapi_message_openattach($copyFrom, (int) $attachProps[PR_ATTACH_NUM]);
Loading history...
2429
				$attachNewResourceMsg = mapi_message_createattach($copyTo);
0 ignored issues
show
The function mapi_message_createattach was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

2429
				$attachNewResourceMsg = /** @scrutinizer ignore-call */ mapi_message_createattach($copyTo);
Loading history...
2430
				mapi_copyto($attachOld, [], [], $attachNewResourceMsg, 0);
0 ignored issues
show
The function mapi_copyto was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

2430
				/** @scrutinizer ignore-call */ 
2431
    mapi_copyto($attachOld, [], [], $attachNewResourceMsg, 0);
Loading history...
2431
				mapi_savechanges($attachNewResourceMsg);
0 ignored issues
show
The function mapi_savechanges was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

2431
				/** @scrutinizer ignore-call */ 
2432
    mapi_savechanges($attachNewResourceMsg);
Loading history...
2432
			}
2433
		}
2434
	}
2435
2436
	/**
2437
	 * Function which replaces recipients in copyTo with recipients from copyFrom.
2438
	 *
2439
	 * @param mixed $copyFrom   MAPI_message from which recipients are to be copied
2440
	 * @param mixed $copyTo     MAPI_message to which recipients are to be copied
2441
	 * @param bool  $isDelegate indicates whether delegate is processing
2442
	 *                          so don't copy delegate information to recipient table
2443
	 */
2444
	public function replaceRecipients($copyFrom, $copyTo, $isDelegate = false): void {
2445
		$recipientTable = mapi_message_getrecipienttable($copyFrom);
0 ignored issues
show
The function mapi_message_getrecipienttable was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

2445
		$recipientTable = /** @scrutinizer ignore-call */ mapi_message_getrecipienttable($copyFrom);
Loading history...
2446
2447
		// If delegate, then do not add the delegate in recipients
2448
		if ($isDelegate) {
2449
			$delegate = mapi_getprops($copyFrom, [PR_RECEIVED_BY_EMAIL_ADDRESS]);
0 ignored issues
show
The constant PR_RECEIVED_BY_EMAIL_ADDRESS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
The function mapi_getprops was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

2449
			$delegate = /** @scrutinizer ignore-call */ mapi_getprops($copyFrom, [PR_RECEIVED_BY_EMAIL_ADDRESS]);
Loading history...
2450
			$res = [
2451
				RES_PROPERTY,
2452
				[
2453
					RELOP => RELOP_NE,
2454
					ULPROPTAG => PR_EMAIL_ADDRESS,
0 ignored issues
show
The constant PR_EMAIL_ADDRESS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
2455
					VALUE => [PR_EMAIL_ADDRESS => $delegate[PR_RECEIVED_BY_EMAIL_ADDRESS]],
2456
				],
2457
			];
2458
			$recipients = mapi_table_queryallrows($recipientTable, $this->recipprops, $res);
0 ignored issues
show
The function mapi_table_queryallrows was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

2458
			$recipients = /** @scrutinizer ignore-call */ mapi_table_queryallrows($recipientTable, $this->recipprops, $res);
Loading history...
2459
		}
2460
		else {
2461
			$recipients = mapi_table_queryallrows($recipientTable, $this->recipprops);
2462
		}
2463
2464
		$copyToRecipientTable = mapi_message_getrecipienttable($copyTo);
2465
		$copyToRecipientRows = mapi_table_queryallrows($copyToRecipientTable, [PR_ROWID]);
0 ignored issues
show
The constant PR_ROWID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
2466
2467
		mapi_message_modifyrecipients($copyTo, MODRECIP_REMOVE, $copyToRecipientRows);
0 ignored issues
show
The function mapi_message_modifyrecipients was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

2467
		/** @scrutinizer ignore-call */ 
2468
  mapi_message_modifyrecipients($copyTo, MODRECIP_REMOVE, $copyToRecipientRows);
Loading history...
2468
		mapi_message_modifyrecipients($copyTo, MODRECIP_ADD, $recipients);
2469
	}
2470
2471
	/**
2472
	 * Function creates meeting item in resource's calendar.
2473
	 *
2474
	 * @param resource $message  MAPI_message which is to create in resource's calendar
2475
	 * @param bool     $cancel   cancel meeting
2476
	 * @param mixed    $prefix   prefix for subject of meeting
2477
	 * @param mixed    $basedate
2478
	 *
2479
	 * @return (mixed|resource)[][]
2480
	 *
2481
	 * @psalm-return list<array{store: resource, folder: mixed, msg: mixed}>
2482
	 */
2483
	public function bookResources($message, $cancel, $prefix, $basedate = false): array {
2484
		if (!$this->enableDirectBooking) {
2485
			return [];
2486
		}
2487
2488
		// Get the properties of the message
2489
		$messageprops = mapi_getprops($message);
0 ignored issues
show
The function mapi_getprops was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

2489
		$messageprops = /** @scrutinizer ignore-call */ mapi_getprops($message);
Loading history...
2490
2491
		if ($basedate) {
2492
			$recurrItemProps = mapi_getprops($this->message, [$this->proptags['goid'], $this->proptags['goid2'], $this->proptags['timezone_data'], $this->proptags['timezone'], PR_OWNER_APPT_ID]);
0 ignored issues
show
The constant PR_OWNER_APPT_ID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
2493
2494
			$messageprops[$this->proptags['goid']] = $this->setBasedateInGlobalID($recurrItemProps[$this->proptags['goid']], $basedate);
2495
			$messageprops[$this->proptags['goid2']] = $recurrItemProps[$this->proptags['goid2']];
2496
2497
			// Delete properties which are not needed.
2498
			$deleteProps = [$this->proptags['basedate'], PR_DISPLAY_NAME, PR_ATTACHMENT_FLAGS, PR_ATTACHMENT_HIDDEN, PR_ATTACHMENT_LINKID, PR_ATTACH_FLAGS, PR_ATTACH_METHOD];
0 ignored issues
show
The constant PR_ATTACH_METHOD was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
The constant PR_ATTACHMENT_LINKID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
The constant PR_ATTACHMENT_FLAGS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
The constant PR_ATTACH_FLAGS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
The constant PR_DISPLAY_NAME was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
The constant PR_ATTACHMENT_HIDDEN was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
2499
			foreach ($deleteProps as $propID) {
2500
				if (isset($messageprops[$propID])) {
2501
					unset($messageprops[$propID]);
2502
				}
2503
			}
2504
2505
			if (isset($messageprops[$this->proptags['recurring']])) {
2506
				$messageprops[$this->proptags['recurring']] = false;
2507
			}
2508
2509
			// Set Outlook properties
2510
			$messageprops[$this->proptags['clipstart']] = $messageprops[$this->proptags['startdate']];
2511
			$messageprops[$this->proptags['clipend']] = $messageprops[$this->proptags['duedate']];
2512
			$messageprops[$this->proptags['timezone_data']] = $recurrItemProps[$this->proptags['timezone_data']];
2513
			$messageprops[$this->proptags['timezone']] = $recurrItemProps[$this->proptags['timezone']];
2514
			$messageprops[$this->proptags['attendee_critical_change']] = time();
2515
			$messageprops[$this->proptags['owner_critical_change']] = time();
2516
		}
2517
2518
		// Get resource recipients
2519
		$getResourcesRestriction = [
2520
			RES_PROPERTY,
2521
			[
2522
				RELOP => RELOP_EQ,	// Equals recipient type 3: Resource
2523
				ULPROPTAG => PR_RECIPIENT_TYPE,
0 ignored issues
show
The constant PR_RECIPIENT_TYPE was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
2524
				VALUE => [PR_RECIPIENT_TYPE => MAPI_BCC],
2525
			],
2526
		];
2527
		$recipienttable = mapi_message_getrecipienttable($message);
0 ignored issues
show
The function mapi_message_getrecipienttable was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

2527
		$recipienttable = /** @scrutinizer ignore-call */ mapi_message_getrecipienttable($message);
Loading history...
2528
		$resourceRecipients = mapi_table_queryallrows($recipienttable, $this->recipprops, $getResourcesRestriction);
0 ignored issues
show
The function mapi_table_queryallrows was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

2528
		$resourceRecipients = /** @scrutinizer ignore-call */ mapi_table_queryallrows($recipienttable, $this->recipprops, $getResourcesRestriction);
Loading history...
2529
2530
		$this->errorSetResource = false;
2531
		$resourceRecipData = [];
2532
2533
		// Put appointment into store resource users
2534
		$i = 0;
2535
		$len = count($resourceRecipients);
2536
		while (!$this->errorSetResource && $i < $len) {
2537
			$userStore = $this->openCustomUserStore($resourceRecipients[$i][PR_ENTRYID]);
2538
2539
			// Open root folder
2540
			$userRoot = mapi_msgstore_openentry($userStore, null);
0 ignored issues
show
The function mapi_msgstore_openentry was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

2540
			$userRoot = /** @scrutinizer ignore-call */ mapi_msgstore_openentry($userStore, null);
Loading history...
2541
2542
			// Get calendar entryID
2543
			$userRootProps = mapi_getprops($userRoot, [PR_STORE_ENTRYID, PR_IPM_APPOINTMENT_ENTRYID, PR_FREEBUSY_ENTRYIDS]);
0 ignored issues
show
The constant PR_STORE_ENTRYID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
The constant PR_IPM_APPOINTMENT_ENTRYID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
The constant PR_FREEBUSY_ENTRYIDS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
2544
2545
			// Open Calendar folder
2546
			$accessToFolder = false;
0 ignored issues
show
The assignment to $accessToFolder is dead and can be removed.
Loading history...
2547
2548
			try {
2549
				// @FIXME this checks delegate has access to resource's calendar folder
2550
				// but it should use boss' credentials
2551
2552
				$accessToFolder = $this->checkCalendarWriteAccess($this->store);
2553
				if ($accessToFolder) {
2554
					$calFolder = mapi_msgstore_openentry($userStore, $userRootProps[PR_IPM_APPOINTMENT_ENTRYID]);
2555
				}
2556
			}
2557
			catch (MAPIException $e) {
2558
				$e->setHandled();
2559
				$this->errorSetResource = 1; // No access
2560
			}
2561
2562
			if ($accessToFolder) {
2563
				/**
2564
				 * Get the LocalFreebusy message that contains the properties that
2565
				 * are set to accept or decline resource meeting requests.
2566
				 */
2567
				$localFreebusyMsg = FreeBusy::getLocalFreeBusyMessage($userStore);
2568
				if ($localFreebusyMsg) {
2569
					$props = mapi_getprops($localFreebusyMsg, [PR_SCHDINFO_AUTO_ACCEPT_APPTS, PR_SCHDINFO_DISALLOW_RECURRING_APPTS, PR_SCHDINFO_DISALLOW_OVERLAPPING_APPTS]);
0 ignored issues
show
The constant PR_SCHDINFO_DISALLOW_OVERLAPPING_APPTS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
The constant PR_SCHDINFO_AUTO_ACCEPT_APPTS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
The constant PR_SCHDINFO_DISALLOW_RECURRING_APPTS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
2570
2571
					$acceptMeetingRequests = isset($props[PR_SCHDINFO_AUTO_ACCEPT_APPTS]) ? $props[PR_SCHDINFO_AUTO_ACCEPT_APPTS] : false;
2572
					$declineRecurringMeetingRequests = isset($props[PR_SCHDINFO_DISALLOW_RECURRING_APPTS]) ? $props[PR_SCHDINFO_DISALLOW_RECURRING_APPTS] : false;
2573
					$declineConflictingMeetingRequests = isset($props[PR_SCHDINFO_DISALLOW_OVERLAPPING_APPTS]) ? $props[PR_SCHDINFO_DISALLOW_OVERLAPPING_APPTS] : false;
2574
2575
					if (!$acceptMeetingRequests) {
2576
						/*
2577
						 * When a resource has not been set to automatically accept meeting requests,
2578
						 * the meeting request has to be sent to him rather than being put directly into
2579
						 * his calendar. No error should be returned.
2580
						 */
2581
						// $errorSetResource = 2;
2582
						$this->nonAcceptingResources[] = $resourceRecipients[$i];
2583
					}
2584
					else {
2585
						if ($declineRecurringMeetingRequests && !$cancel) {
2586
							// Check if appointment is recurring
2587
							if ($messageprops[$this->proptags['recurring']]) {
2588
								$this->errorSetResource = 3;
2589
							}
2590
						}
2591
						if ($declineConflictingMeetingRequests && !$cancel) {
2592
							// Check for conflicting items
2593
							if ($calFolder && $this->isMeetingConflicting($message, $userStore, $calFolder)) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $calFolder does not seem to be defined for all execution paths leading up to this point.
Loading history...
2594
								$this->errorSetResource = 4; // Conflict
2595
							}
2596
						}
2597
					}
2598
				}
2599
			}
2600
2601
			if (!$this->errorSetResource && $accessToFolder) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->errorSetResource of type false|integer is loosely compared to false; this is ambiguous if the integer can be 0. You might want to explicitly use === false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
2602
				/**
2603
				 * First search on GlobalID(0x3)
2604
				 * If (recurring and occurrence) If Resource was booked for only this occurrence then Resource should have only this occurrence in Calendar and not whole series.
2605
				 * If (normal meeting) then GlobalID(0x3) and CleanGlobalID(0x23) are same, so doesn't matter if search is based on GlobalID.
2606
				 */
2607
				$rows = $this->findCalendarItems($messageprops[$this->proptags['goid']], $calFolder);
2608
2609
				/*
2610
				 * If no entry is found then
2611
				 * 1) Resource doesn't have meeting in Calendar. Seriously!!
2612
				 * OR
2613
				 * 2) We were looking for occurrence item but Resource has whole series
2614
				 */
2615
				if (empty($rows)) {
2616
					/**
2617
					 * Now search on CleanGlobalID(0x23) WHY???
2618
					 * Because we are looking recurring item.
2619
					 *
2620
					 * Possible results of this search
2621
					 * 1) If Resource was booked for more than one occurrences then this search will return all those occurrence because search is perform on CleanGlobalID
2622
					 * 2) If Resource was booked for whole series then it should return series.
2623
					 */
2624
					$rows = $this->findCalendarItems($messageprops[$this->proptags['goid2']], $calFolder, true);
2625
2626
					$newResourceMsg = false;
2627
					if (!empty($rows)) {
2628
						// Since we are looking for recurring item, open every result and check for 'recurring' property.
2629
						foreach ($rows as $row) {
2630
							$ResourceMsg = mapi_msgstore_openentry($userStore, $row);
2631
							$ResourceMsgProps = mapi_getprops($ResourceMsg, [$this->proptags['recurring']]);
2632
2633
							if (isset($ResourceMsgProps[$this->proptags['recurring']]) && $ResourceMsgProps[$this->proptags['recurring']]) {
2634
								$newResourceMsg = $ResourceMsg;
2635
								break;
2636
							}
2637
						}
2638
					}
2639
2640
					// Still no results found. I giveup, create new message.
2641
					if (!$newResourceMsg) {
2642
						$newResourceMsg = mapi_folder_createmessage($calFolder);
0 ignored issues
show
The function mapi_folder_createmessage was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

2642
						$newResourceMsg = /** @scrutinizer ignore-call */ mapi_folder_createmessage($calFolder);
Loading history...
2643
					}
2644
				}
2645
				else {
2646
					$newResourceMsg = mapi_msgstore_openentry($userStore, $rows[0]);
2647
				}
2648
2649
				// Prefix the subject if needed
2650
				if ($prefix && isset($messageprops[PR_SUBJECT])) {
0 ignored issues
show
The constant PR_SUBJECT was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
2651
					$messageprops[PR_SUBJECT] = $prefix . $messageprops[PR_SUBJECT];
2652
				}
2653
2654
				// Set status to cancelled if needed
2655
				$messageprops[$this->proptags['busystatus']] = fbBusy; // The default status (Busy)
2656
				if ($cancel) {
2657
					$messageprops[$this->proptags['meetingstatus']] = olMeetingCanceled; // The meeting has been canceled
2658
					$messageprops[$this->proptags['busystatus']] = fbFree; // Free
2659
				}
2660
				else {
2661
					$messageprops[$this->proptags['meetingstatus']] = olMeetingReceived; // The recipient is receiving the request
2662
				}
2663
				$messageprops[$this->proptags['responsestatus']] = olResponseAccepted; // The resource automatically accepts the appointment
2664
2665
				$messageprops[PR_MESSAGE_CLASS] = 'IPM.Appointment';
0 ignored issues
show
The constant PR_MESSAGE_CLASS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
2666
2667
				// Remove the PR_ICON_INDEX as it is not needed in the sent message.
2668
				$messageprops[PR_ICON_INDEX] = null;
0 ignored issues
show
The constant PR_ICON_INDEX was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
2669
				$messageprops[PR_RESPONSE_REQUESTED] = true;
0 ignored issues
show
The constant PR_RESPONSE_REQUESTED was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
2670
2671
				// get the store of organizer, in case of delegates it will be delegate store
2672
				$defaultStore = $this->openDefaultStore();
2673
2674
				$storeProps = mapi_getprops($this->store, [PR_ENTRYID]);
2675
				$defaultStoreProps = mapi_getprops($defaultStore, [PR_ENTRYID]);
2676
2677
				// @FIXME use entryid comparison functions here
2678
				if ($storeProps[PR_ENTRYID] !== $defaultStoreProps[PR_ENTRYID]) {
2679
					// get delegate information
2680
					$addrInfo = $this->getOwnerAddress($defaultStore, false);
2681
2682
					if (!empty($addrInfo)) {
2683
						list($ownername, $owneremailaddr, $owneraddrtype, $ownerentryid, $ownersearchkey) = $addrInfo;
2684
2685
						$messageprops[PR_SENDER_EMAIL_ADDRESS] = $owneremailaddr;
0 ignored issues
show
The constant PR_SENDER_EMAIL_ADDRESS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
2686
						$messageprops[PR_SENDER_NAME] = $ownername;
0 ignored issues
show
The constant PR_SENDER_NAME was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
2687
						$messageprops[PR_SENDER_ADDRTYPE] = $owneraddrtype;
0 ignored issues
show
The constant PR_SENDER_ADDRTYPE was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
2688
						$messageprops[PR_SENDER_ENTRYID] = $ownerentryid;
0 ignored issues
show
The constant PR_SENDER_ENTRYID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
2689
						$messageprops[PR_SENDER_SEARCH_KEY] = $ownersearchkey;
0 ignored issues
show
The constant PR_SENDER_SEARCH_KEY was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
2690
					}
2691
2692
					// get delegator information
2693
					$addrInfo = $this->getOwnerAddress($this->store, false);
2694
2695
					if (!empty($addrInfo)) {
2696
						list($ownername, $owneremailaddr, $owneraddrtype, $ownerentryid, $ownersearchkey) = $addrInfo;
2697
2698
						$messageprops[PR_SENT_REPRESENTING_EMAIL_ADDRESS] = $owneremailaddr;
0 ignored issues
show
The constant PR_SENT_REPRESENTING_EMAIL_ADDRESS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
2699
						$messageprops[PR_SENT_REPRESENTING_NAME] = $ownername;
0 ignored issues
show
The constant PR_SENT_REPRESENTING_NAME was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
2700
						$messageprops[PR_SENT_REPRESENTING_ADDRTYPE] = $owneraddrtype;
0 ignored issues
show
The constant PR_SENT_REPRESENTING_ADDRTYPE was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
2701
						$messageprops[PR_SENT_REPRESENTING_ENTRYID] = $ownerentryid;
0 ignored issues
show
The constant PR_SENT_REPRESENTING_ENTRYID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
2702
						$messageprops[PR_SENT_REPRESENTING_SEARCH_KEY] = $ownersearchkey;
0 ignored issues
show
The constant PR_SENT_REPRESENTING_SEARCH_KEY was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
2703
					}
2704
				}
2705
				else {
2706
					// get organizer information
2707
					$addrInfo = $this->getOwnerAddress($this->store);
2708
2709
					if (!empty($addrInfo)) {
2710
						list($ownername, $owneremailaddr, $owneraddrtype, $ownerentryid, $ownersearchkey) = $addrInfo;
2711
2712
						$messageprops[PR_SENDER_EMAIL_ADDRESS] = $owneremailaddr;
2713
						$messageprops[PR_SENDER_NAME] = $ownername;
2714
						$messageprops[PR_SENDER_ADDRTYPE] = $owneraddrtype;
2715
						$messageprops[PR_SENDER_ENTRYID] = $ownerentryid;
2716
						$messageprops[PR_SENDER_SEARCH_KEY] = $ownersearchkey;
2717
2718
						$messageprops[PR_SENT_REPRESENTING_EMAIL_ADDRESS] = $owneremailaddr;
2719
						$messageprops[PR_SENT_REPRESENTING_NAME] = $ownername;
2720
						$messageprops[PR_SENT_REPRESENTING_ADDRTYPE] = $owneraddrtype;
2721
						$messageprops[PR_SENT_REPRESENTING_ENTRYID] = $ownerentryid;
2722
						$messageprops[PR_SENT_REPRESENTING_SEARCH_KEY] = $ownersearchkey;
2723
					}
2724
				}
2725
2726
				$messageprops[$this->proptags['replytime']] = time();
2727
2728
				if ($basedate && isset($ResourceMsgProps[$this->proptags['recurring']]) && $ResourceMsgProps[$this->proptags['recurring']]) {
2729
					$recurr = new Recurrence($userStore, $newResourceMsg);
2730
2731
					// Copy recipients list
2732
					$reciptable = mapi_message_getrecipienttable($message);
2733
					$recips = mapi_table_queryallrows($reciptable, $this->recipprops);
2734
2735
					// add owner to recipient table
2736
					$this->addOrganizer($messageprops, $recips, true);
2737
2738
					// Update occurrence
2739
					if ($recurr->isException($basedate)) {
2740
						$recurr->modifyException($messageprops, $basedate, $recips);
2741
					}
2742
					else {
2743
						$recurr->createException($messageprops, $basedate, false, $recips);
2744
					}
2745
				}
2746
				else {
2747
					mapi_setprops($newResourceMsg, $messageprops);
0 ignored issues
show
The function mapi_setprops was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

2747
					/** @scrutinizer ignore-call */ 
2748
     mapi_setprops($newResourceMsg, $messageprops);
Loading history...
2748
2749
					// Copy attachments
2750
					$this->replaceAttachments($message, $newResourceMsg);
2751
2752
					// Copy all recipients too
2753
					$this->replaceRecipients($message, $newResourceMsg);
2754
2755
					// Now add organizer also to recipient table
2756
					$recips = [];
2757
					$this->addOrganizer($messageprops, $recips);
2758
2759
					mapi_message_modifyrecipients($newResourceMsg, MODRECIP_ADD, $recips);
0 ignored issues
show
The function mapi_message_modifyrecipients was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

2759
					/** @scrutinizer ignore-call */ 
2760
     mapi_message_modifyrecipients($newResourceMsg, MODRECIP_ADD, $recips);
Loading history...
2760
				}
2761
2762
				mapi_savechanges($newResourceMsg);
0 ignored issues
show
The function mapi_savechanges was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

2762
				/** @scrutinizer ignore-call */ 
2763
    mapi_savechanges($newResourceMsg);
Loading history...
2763
2764
				$resourceRecipData[] = [
2765
					'store' => $userStore,
2766
					'folder' => $calFolder,
2767
					'msg' => $newResourceMsg,
2768
				];
2769
				$this->includesResources = true;
2770
			}
2771
			else {
2772
				/*
2773
				 * If no other errors occurred and you have no access to the
2774
				 * folder of the resource, throw an error=1.
2775
				 */
2776
				if (!$this->errorSetResource) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->errorSetResource of type false|integer is loosely compared to false; this is ambiguous if the integer can be 0. You might want to explicitly use === false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
2777
					$this->errorSetResource = 1;
2778
				}
2779
2780
				for ($j = 0, $len = count($resourceRecipData); $j < $len; ++$j) {
2781
					// Get the EntryID
2782
					$props = mapi_message_getprops($resourceRecipData[$j]['msg']);
0 ignored issues
show
The function mapi_message_getprops was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

2782
					$props = /** @scrutinizer ignore-call */ mapi_message_getprops($resourceRecipData[$j]['msg']);
Loading history...
2783
2784
					mapi_folder_deletemessages($resourceRecipData[$j]['folder'], [$props[PR_ENTRYID]], DELETE_HARD_DELETE);
0 ignored issues
show
The function mapi_folder_deletemessages was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

2784
					/** @scrutinizer ignore-call */ 
2785
     mapi_folder_deletemessages($resourceRecipData[$j]['folder'], [$props[PR_ENTRYID]], DELETE_HARD_DELETE);
Loading history...
2785
				}
2786
				$this->recipientDisplayname = $resourceRecipients[$i][PR_DISPLAY_NAME];
2787
			}
2788
			++$i;
2789
		}
2790
2791
		/*
2792
		 * Set the BCC-recipients (resources) tackstatus to accepted.
2793
		 */
2794
		// Get resource recipients
2795
		$getResourcesRestriction = [
2796
			RES_PROPERTY,
2797
			[
2798
				RELOP => RELOP_EQ,	// Equals recipient type 3: Resource
2799
				ULPROPTAG => PR_RECIPIENT_TYPE,
2800
				VALUE => [PR_RECIPIENT_TYPE => MAPI_BCC],
2801
			],
2802
		];
2803
		$recipienttable = mapi_message_getrecipienttable($message);
2804
		$resourceRecipients = mapi_table_queryallrows($recipienttable, $this->recipprops, $getResourcesRestriction);
2805
		if (!empty($resourceRecipients)) {
2806
			// Set Tracking status of resource recipients to olResponseAccepted (3)
2807
			for ($i = 0, $len = count($resourceRecipients); $i < $len; ++$i) {
2808
				$resourceRecipients[$i][PR_RECIPIENT_TRACKSTATUS] = olRecipientTrackStatusAccepted;
0 ignored issues
show
The constant PR_RECIPIENT_TRACKSTATUS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
2809
				$resourceRecipients[$i][PR_RECIPIENT_TRACKSTATUS_TIME] = time();
0 ignored issues
show
The constant PR_RECIPIENT_TRACKSTATUS_TIME was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
2810
			}
2811
			mapi_message_modifyrecipients($message, MODRECIP_MODIFY, $resourceRecipients);
2812
		}
2813
2814
		return $resourceRecipData;
2815
	}
2816
2817
	/**
2818
	 * Function which save an exception into recurring item.
2819
	 *
2820
	 * @param resource $recurringItem  reference to MAPI_message of recurring item
2821
	 * @param resource $occurrenceItem reference to MAPI_message of occurrence
2822
	 * @param string   $basedate       basedate of occurrence
2823
	 * @param bool     $move           if true then occurrence item is deleted
2824
	 * @param bool     $tentative      true if user has tentatively accepted it or false if user has accepted it
2825
	 * @param bool     $userAction     true if user has manually responded to meeting request
2826
	 * @param resource $store          user store
2827
	 * @param bool     $isDelegate     true if delegate is processing this meeting request
2828
	 */
2829
	public function acceptException(&$recurringItem, &$occurrenceItem, $basedate, $move, $tentative, $userAction, $store, $isDelegate = false): void {
2830
		$recurr = new Recurrence($store, $recurringItem);
2831
2832
		// Copy properties from meeting request
2833
		$exception_props = mapi_getprops($occurrenceItem);
0 ignored issues
show
The function mapi_getprops was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

2833
		$exception_props = /** @scrutinizer ignore-call */ mapi_getprops($occurrenceItem);
Loading history...
2834
2835
		// Copy recipients list
2836
		$reciptable = mapi_message_getrecipienttable($occurrenceItem);
0 ignored issues
show
The function mapi_message_getrecipienttable was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

2836
		$reciptable = /** @scrutinizer ignore-call */ mapi_message_getrecipienttable($occurrenceItem);
Loading history...
2837
		// If delegate, then do not add the delegate in recipients
2838
		if ($isDelegate) {
2839
			$delegate = mapi_getprops($this->message, [PR_RECEIVED_BY_EMAIL_ADDRESS]);
0 ignored issues
show
The constant PR_RECEIVED_BY_EMAIL_ADDRESS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
2840
			$res = [
2841
				RES_PROPERTY,
2842
				[
2843
					RELOP => RELOP_NE,
2844
					ULPROPTAG => PR_EMAIL_ADDRESS,
0 ignored issues
show
The constant PR_EMAIL_ADDRESS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
2845
					VALUE => [PR_EMAIL_ADDRESS => $delegate[PR_RECEIVED_BY_EMAIL_ADDRESS]],
2846
				],
2847
			];
2848
			$recips = mapi_table_queryallrows($reciptable, $this->recipprops, $res);
0 ignored issues
show
The function mapi_table_queryallrows was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

2848
			$recips = /** @scrutinizer ignore-call */ mapi_table_queryallrows($reciptable, $this->recipprops, $res);
Loading history...
2849
		}
2850
		else {
2851
			$recips = mapi_table_queryallrows($reciptable, $this->recipprops);
2852
		}
2853
2854
		// add owner to recipient table
2855
		$this->addOrganizer($exception_props, $recips, true);
2856
2857
		// add delegator to meetings
2858
		if ($isDelegate) {
2859
			$this->addDelegator($exception_props, $recips);
2860
		}
2861
2862
		$exception_props[$this->proptags['meetingstatus']] = olMeetingReceived;
2863
		$exception_props[$this->proptags['responsestatus']] = $userAction ? ($tentative ? olResponseTentative : olResponseAccepted) : olResponseNotResponded;
2864
2865
		if (isset($exception_props[$this->proptags['intendedbusystatus']])) {
2866
			if ($tentative && $exception_props[$this->proptags['intendedbusystatus']] !== fbFree) {
2867
				$exception_props[$this->proptags['busystatus']] = fbTentative;
2868
			}
2869
			else {
2870
				$exception_props[$this->proptags['busystatus']] = $exception_props[$this->proptags['intendedbusystatus']];
2871
			}
2872
		// we already have intendedbusystatus value in $exception_props so no need to copy it
2873
		}
2874
		else {
2875
			$exception_props[$this->proptags['busystatus']] = $tentative ? fbTentative : fbBusy;
2876
		}
2877
2878
		if ($userAction) {
2879
			$addrInfo = $this->getOwnerAddress($this->store);
2880
2881
			// if user has responded then set replytime and name
2882
			$exception_props[$this->proptags['replytime']] = time();
2883
			if (!empty($addrInfo)) {
2884
				$exception_props[$this->proptags['apptreplyname']] = $addrInfo[0];
2885
			}
2886
		}
2887
2888
		if ($recurr->isException($basedate)) {
2889
			$recurr->modifyException($exception_props, $basedate, $recips, $occurrenceItem);
2890
		}
2891
		else {
2892
			$recurr->createException($exception_props, $basedate, false, $recips, $occurrenceItem);
2893
		}
2894
2895
		// Move the occurrenceItem to the waste basket
2896
		if ($move) {
2897
			$wastebasket = $this->openDefaultWastebasket($this->openDefaultStore());
2898
			$sourcefolder = mapi_msgstore_openentry($store, $exception_props[PR_PARENT_ENTRYID]);
0 ignored issues
show
The function mapi_msgstore_openentry was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

2898
			$sourcefolder = /** @scrutinizer ignore-call */ mapi_msgstore_openentry($store, $exception_props[PR_PARENT_ENTRYID]);
Loading history...
The constant PR_PARENT_ENTRYID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
2899
			mapi_folder_copymessages($sourcefolder, [$exception_props[PR_ENTRYID]], $wastebasket, MESSAGE_MOVE);
0 ignored issues
show
The function mapi_folder_copymessages was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

2899
			/** @scrutinizer ignore-call */ 
2900
   mapi_folder_copymessages($sourcefolder, [$exception_props[PR_ENTRYID]], $wastebasket, MESSAGE_MOVE);
Loading history...
2900
		}
2901
2902
		mapi_savechanges($recurringItem);
0 ignored issues
show
The function mapi_savechanges was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

2902
		/** @scrutinizer ignore-call */ 
2903
  mapi_savechanges($recurringItem);
Loading history...
2903
	}
2904
2905
	/**
2906
	 * Function which merges an exception mapi message to recurring message.
2907
	 * This will be used when we receive recurring meeting request and we already have an exception message
2908
	 * of same meeting in calendar and we need to remove that exception message and add it to attachment table
2909
	 * of recurring meeting.
2910
	 *
2911
	 * @param resource $recurringItem  reference to MAPI_message of recurring item
2912
	 * @param resource $occurrenceItem reference to MAPI_message of occurrence
2913
	 * @param mixed    $basedate       basedate of occurrence
2914
	 * @param resource $store          user store
2915
	 */
2916
	public function mergeException(&$recurringItem, &$occurrenceItem, $basedate, $store): void {
2917
		$recurr = new Recurrence($store, $recurringItem);
2918
2919
		// Copy properties from meeting request
2920
		$exception_props = mapi_getprops($occurrenceItem);
0 ignored issues
show
The function mapi_getprops was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

2920
		$exception_props = /** @scrutinizer ignore-call */ mapi_getprops($occurrenceItem);
Loading history...
2921
2922
		// Get recipient list from message and add it to exception attachment
2923
		$reciptable = mapi_message_getrecipienttable($occurrenceItem);
0 ignored issues
show
The function mapi_message_getrecipienttable was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

2923
		$reciptable = /** @scrutinizer ignore-call */ mapi_message_getrecipienttable($occurrenceItem);
Loading history...
2924
		$recips = mapi_table_queryallrows($reciptable, $this->recipprops);
0 ignored issues
show
The function mapi_table_queryallrows was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

2924
		$recips = /** @scrutinizer ignore-call */ mapi_table_queryallrows($reciptable, $this->recipprops);
Loading history...
2925
2926
		if ($recurr->isException($basedate)) {
2927
			$recurr->modifyException($exception_props, $basedate, $recips, $occurrenceItem);
2928
		}
2929
		else {
2930
			$recurr->createException($exception_props, $basedate, false, $recips, $occurrenceItem);
2931
		}
2932
2933
		// Move the occurrenceItem to the waste basket
2934
		$wastebasket = $this->openDefaultWastebasket($this->openDefaultStore());
2935
		$sourcefolder = mapi_msgstore_openentry($store, $exception_props[PR_PARENT_ENTRYID]);
0 ignored issues
show
The function mapi_msgstore_openentry was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

2935
		$sourcefolder = /** @scrutinizer ignore-call */ mapi_msgstore_openentry($store, $exception_props[PR_PARENT_ENTRYID]);
Loading history...
The constant PR_PARENT_ENTRYID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
2936
		mapi_folder_copymessages($sourcefolder, [$exception_props[PR_ENTRYID]], $wastebasket, MESSAGE_MOVE);
0 ignored issues
show
The function mapi_folder_copymessages was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

2936
		/** @scrutinizer ignore-call */ 
2937
  mapi_folder_copymessages($sourcefolder, [$exception_props[PR_ENTRYID]], $wastebasket, MESSAGE_MOVE);
Loading history...
2937
2938
		mapi_savechanges($recurringItem);
0 ignored issues
show
The function mapi_savechanges was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

2938
		/** @scrutinizer ignore-call */ 
2939
  mapi_savechanges($recurringItem);
Loading history...
2939
	}
2940
2941
	/**
2942
	 * Function which submits meeting request based on arguments passed to it.
2943
	 *
2944
	 * @param resource $message        MAPI_message whose meeting request is to be sent
2945
	 * @param bool     $cancel         if true send request, else send cancellation
2946
	 * @param mixed    $prefix         subject prefix
2947
	 * @param mixed    $basedate       basedate for an occurrence
2948
	 * @param mixed    $recurObject    recurrence object of mr
2949
	 * @param bool     $copyExceptions When sending update mail for recurring item then we don't send exceptions in attachments
2950
	 * @param mixed    $modifiedRecips
2951
	 * @param mixed    $deletedRecips
2952
	 */
2953
	public function submitMeetingRequest($message, $cancel, $prefix, $basedate = false, $recurObject = false, $copyExceptions = true, $modifiedRecips = false, $deletedRecips = false): void {
2954
		$newmessageprops = $messageprops = mapi_getprops($this->message);
0 ignored issues
show
The function mapi_getprops was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

2954
		$newmessageprops = $messageprops = /** @scrutinizer ignore-call */ mapi_getprops($this->message);
Loading history...
2955
		$new = $this->createOutgoingMessage();
2956
2957
		// Copy the entire message into the new meeting request message
2958
		if ($basedate) {
2959
			// messageprops contains properties of whole recurring series
2960
			// and newmessageprops contains properties of exception item
2961
			$newmessageprops = mapi_getprops($message);
2962
2963
			// Ensure that the correct basedate is set in the new message
2964
			$newmessageprops[$this->proptags['basedate']] = $basedate;
2965
2966
			// Set isRecurring to false, because this is an exception
2967
			$newmessageprops[$this->proptags['recurring']] = false;
2968
2969
			// set LID_IS_EXCEPTION to true
2970
			$newmessageprops[$this->proptags['is_exception']] = true;
2971
2972
			// Set to high importance
2973
			if ($cancel) {
2974
				$newmessageprops[PR_IMPORTANCE] = IMPORTANCE_HIGH;
0 ignored issues
show
The constant PR_IMPORTANCE was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
2975
			}
2976
2977
			// Set startdate and enddate of exception
2978
			if ($cancel && $recurObject) {
2979
				$newmessageprops[$this->proptags['startdate']] = $recurObject->getOccurrenceStart($basedate);
2980
				$newmessageprops[$this->proptags['duedate']] = $recurObject->getOccurrenceEnd($basedate);
2981
			}
2982
2983
			// Set basedate in guid (0x3)
2984
			$newmessageprops[$this->proptags['goid']] = $this->setBasedateInGlobalID($messageprops[$this->proptags['goid2']], $basedate);
2985
			$newmessageprops[$this->proptags['goid2']] = $messageprops[$this->proptags['goid2']];
2986
			$newmessageprops[PR_OWNER_APPT_ID] = $messageprops[PR_OWNER_APPT_ID];
0 ignored issues
show
The constant PR_OWNER_APPT_ID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
2987
2988
			// Get deleted recipiets from exception msg
2989
			$restriction = [
2990
				RES_AND,
2991
				[
2992
					[
2993
						RES_BITMASK,
2994
						[
2995
							ULTYPE => BMR_NEZ,
2996
							ULPROPTAG => PR_RECIPIENT_FLAGS,
0 ignored issues
show
The constant PR_RECIPIENT_FLAGS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
2997
							ULMASK => recipExceptionalDeleted,
2998
						],
2999
					],
3000
					[
3001
						RES_BITMASK,
3002
						[
3003
							ULTYPE => BMR_EQZ,
3004
							ULPROPTAG => PR_RECIPIENT_FLAGS,
3005
							ULMASK => recipOrganizer,
3006
						],
3007
					],
3008
				],
3009
			];
3010
3011
			// In direct-booking mode, we don't need to send cancellations to resources
3012
			if ($this->enableDirectBooking) {
3013
				$restriction[1][] = [
3014
					RES_PROPERTY,
3015
					[
3016
						RELOP => RELOP_NE,	// Does not equal recipient type: MAPI_BCC (Resource)
3017
						ULPROPTAG => PR_RECIPIENT_TYPE,
0 ignored issues
show
The constant PR_RECIPIENT_TYPE was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
3018
						VALUE => [PR_RECIPIENT_TYPE => MAPI_BCC],
3019
					],
3020
				];
3021
			}
3022
3023
			$recipienttable = mapi_message_getrecipienttable($message);
0 ignored issues
show
The function mapi_message_getrecipienttable was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

3023
			$recipienttable = /** @scrutinizer ignore-call */ mapi_message_getrecipienttable($message);
Loading history...
3024
			$recipients = mapi_table_queryallrows($recipienttable, $this->recipprops, $restriction);
0 ignored issues
show
The function mapi_table_queryallrows was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

3024
			$recipients = /** @scrutinizer ignore-call */ mapi_table_queryallrows($recipienttable, $this->recipprops, $restriction);
Loading history...
3025
3026
			if (!$deletedRecips) {
3027
				$deletedRecips = array_merge([], $recipients);
3028
			}
3029
			else {
3030
				$deletedRecips = array_merge($deletedRecips, $recipients);
3031
			}
3032
		}
3033
3034
		// Remove the PR_ICON_INDEX as it is not needed in the sent message.
3035
		$newmessageprops[PR_ICON_INDEX] = null;
0 ignored issues
show
The constant PR_ICON_INDEX was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
3036
		$newmessageprops[PR_RESPONSE_REQUESTED] = true;
0 ignored issues
show
The constant PR_RESPONSE_REQUESTED was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
3037
3038
		// PR_START_DATE and PR_END_DATE will be used by outlook to show the position in the calendar
3039
		$newmessageprops[PR_START_DATE] = $newmessageprops[$this->proptags['startdate']];
0 ignored issues
show
The constant PR_START_DATE was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
3040
		$newmessageprops[PR_END_DATE] = $newmessageprops[$this->proptags['duedate']];
0 ignored issues
show
The constant PR_END_DATE was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
3041
3042
		// Set updatecounter/AppointmentSequenceNumber
3043
		// get the value of latest updatecounter for the whole series and use it
3044
		$newmessageprops[$this->proptags['updatecounter']] = $messageprops[$this->proptags['last_updatecounter']];
3045
3046
		$meetingTimeInfo = $this->getMeetingTimeInfo();
3047
3048
		if ($meetingTimeInfo) {
3049
			// Needs to unset PR_HTML and PR_RTF_COMPRESSED props
3050
			// because while canceling meeting requests with edit text
3051
			// will override the PR_BODY because body value is not consistent with
3052
			// PR_HTML and PR_RTF_COMPRESSED value so in this case PR_RTF_COMPRESSED will
3053
			// get priority which override the PR_BODY value.
3054
			unset($newmessageprops[PR_HTML], $newmessageprops[PR_RTF_COMPRESSED]);
0 ignored issues
show
The constant PR_HTML was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
The constant PR_RTF_COMPRESSED was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
3055
3056
			$newmessageprops[PR_BODY] = $meetingTimeInfo;
0 ignored issues
show
The constant PR_BODY was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
3057
		}
3058
3059
		// Send all recurrence info in mail, if this is a recurrence meeting.
3060
		if (isset($messageprops[$this->proptags['recurring']]) && $messageprops[$this->proptags['recurring']]) {
3061
			if (!empty($messageprops[$this->proptags['recurring_pattern']])) {
3062
				$newmessageprops[$this->proptags['recurring_pattern']] = $messageprops[$this->proptags['recurring_pattern']];
3063
			}
3064
			$newmessageprops[$this->proptags['recurrence_data']] = $messageprops[$this->proptags['recurrence_data']];
3065
			$newmessageprops[$this->proptags['timezone_data']] = $messageprops[$this->proptags['timezone_data']];
3066
			$newmessageprops[$this->proptags['timezone']] = $messageprops[$this->proptags['timezone']];
3067
3068
			if ($recurObject) {
3069
				$this->generateRecurDates($recurObject, $messageprops, $newmessageprops);
3070
			}
3071
		}
3072
3073
		if (isset($newmessageprops[$this->proptags['counter_proposal']])) {
3074
			unset($newmessageprops[$this->proptags['counter_proposal']]);
3075
		}
3076
3077
		// Prefix the subject if needed
3078
		if ($prefix && isset($newmessageprops[PR_SUBJECT])) {
0 ignored issues
show
The constant PR_SUBJECT was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
3079
			$newmessageprops[PR_SUBJECT] = $prefix . $newmessageprops[PR_SUBJECT];
3080
		}
3081
3082
		if (isset($newmessageprops[$this->proptags['categories']]) &&
3083
			!empty($newmessageprops[$this->proptags['categories']])) {
3084
			unset($newmessageprops[$this->proptags['categories']]);
3085
		}
3086
		mapi_setprops($new, $newmessageprops);
0 ignored issues
show
The function mapi_setprops was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

3086
		/** @scrutinizer ignore-call */ 
3087
  mapi_setprops($new, $newmessageprops);
Loading history...
3087
3088
		// Copy attachments
3089
		$this->replaceAttachments($message, $new, $copyExceptions);
3090
3091
		// Retrieve only those recipient who should receive this meeting request.
3092
		$stripResourcesRestriction = [
3093
			RES_AND,
3094
			[
3095
				[
3096
					RES_BITMASK,
3097
					[
3098
						ULTYPE => BMR_EQZ,
3099
						ULPROPTAG => PR_RECIPIENT_FLAGS,
3100
						ULMASK => recipExceptionalDeleted,
3101
					],
3102
				],
3103
				[
3104
					RES_BITMASK,
3105
					[
3106
						ULTYPE => BMR_EQZ,
3107
						ULPROPTAG => PR_RECIPIENT_FLAGS,
3108
						ULMASK => recipOrganizer,
3109
					],
3110
				],
3111
			],
3112
		];
3113
3114
		// In direct-booking mode, resources do not receive a meeting request
3115
		if ($this->enableDirectBooking) {
3116
			$stripResourcesRestriction[1][] = [
3117
				RES_PROPERTY,
3118
				[
3119
					RELOP => RELOP_NE,	// Does not equal recipient type: MAPI_BCC (Resource)
3120
					ULPROPTAG => PR_RECIPIENT_TYPE,
3121
					VALUE => [PR_RECIPIENT_TYPE => MAPI_BCC],
3122
				],
3123
			];
3124
		}
3125
3126
		// If no recipients were explicitly provided, we will send the update to all
3127
		// recipients from the meeting.
3128
		if ($modifiedRecips === false) {
3129
			$recipienttable = mapi_message_getrecipienttable($message);
3130
			$modifiedRecips = mapi_table_queryallrows($recipienttable, $this->recipprops, $stripResourcesRestriction);
3131
3132
			if ($basedate && empty($modifiedRecips)) {
3133
				// Retrieve full list
3134
				$recipienttable = mapi_message_getrecipienttable($this->message);
3135
				$modifiedRecips = mapi_table_queryallrows($recipienttable, $this->recipprops);
3136
3137
				// Save recipients in exceptions
3138
				mapi_message_modifyrecipients($message, MODRECIP_ADD, $modifiedRecips);
0 ignored issues
show
The function mapi_message_modifyrecipients was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

3138
				/** @scrutinizer ignore-call */ 
3139
    mapi_message_modifyrecipients($message, MODRECIP_ADD, $modifiedRecips);
Loading history...
3139
3140
				// Now retrieve only those recipient who should receive this meeting request.
3141
				$modifiedRecips = mapi_table_queryallrows($recipienttable, $this->recipprops, $stripResourcesRestriction);
3142
			}
3143
		}
3144
3145
		// @TODO: handle nonAcceptingResources
3146
		/*
3147
		 * Add resource recipients that did not automatically accept the meeting request.
3148
		 * (note: meaning that they did not decline the meeting request)
3149
		 */ /*
3150
		for($i=0;$i<count($this->nonAcceptingResources);$i++){
3151
			$recipients[] = $this->nonAcceptingResources[$i];
3152
		}*/
3153
3154
		if (!empty($modifiedRecips)) {
3155
			// Strip out the sender/'owner' recipient
3156
			mapi_message_modifyrecipients($new, MODRECIP_ADD, $modifiedRecips);
3157
3158
			// Set some properties that are different in the sent request than
3159
			// in the item in our calendar
3160
3161
			// we should store busystatus value to intendedbusystatus property, because busystatus for outgoing meeting request
3162
			// should always be fbTentative
3163
			$newmessageprops[$this->proptags['intendedbusystatus']] = isset($newmessageprops[$this->proptags['busystatus']]) ? $newmessageprops[$this->proptags['busystatus']] : $messageprops[$this->proptags['busystatus']];
3164
			$newmessageprops[$this->proptags['busystatus']] = fbTentative; // The default status when not accepted
3165
			$newmessageprops[$this->proptags['responsestatus']] = olResponseNotResponded; // The recipient has not responded yet
3166
			$newmessageprops[$this->proptags['attendee_critical_change']] = time();
3167
			$newmessageprops[$this->proptags['owner_critical_change']] = time();
3168
			$newmessageprops[$this->proptags['meetingtype']] = mtgRequest;
3169
3170
			if ($cancel) {
3171
				$newmessageprops[PR_MESSAGE_CLASS] = 'IPM.Schedule.Meeting.Canceled';
0 ignored issues
show
The constant PR_MESSAGE_CLASS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
3172
				$newmessageprops[$this->proptags['meetingstatus']] = olMeetingCanceled; // It's a cancel request
3173
				$newmessageprops[$this->proptags['busystatus']] = fbFree; // set the busy status as free
3174
			}
3175
			else {
3176
				$newmessageprops[PR_MESSAGE_CLASS] = 'IPM.Schedule.Meeting.Request';
3177
				$newmessageprops[$this->proptags['meetingstatus']] = olMeetingReceived; // The recipient is receiving the request
3178
			}
3179
3180
			mapi_setprops($new, $newmessageprops);
3181
			mapi_savechanges($new);
0 ignored issues
show
The function mapi_savechanges was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

3181
			/** @scrutinizer ignore-call */ 
3182
   mapi_savechanges($new);
Loading history...
3182
3183
			// Submit message to non-resource recipients
3184
			mapi_message_submitmessage($new);
0 ignored issues
show
The function mapi_message_submitmessage was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

3184
			/** @scrutinizer ignore-call */ 
3185
   mapi_message_submitmessage($new);
Loading history...
3185
		}
3186
3187
		// Search through the deleted recipients, and see if any of them is also
3188
		// listed as a recipient to whom we have sent an update. As we don't
3189
		// want to send a cancellation message to recipients who will also receive
3190
		// an meeting update, we have to filter those recipients out.
3191
		if ($deletedRecips) {
3192
			$tmp = [];
3193
3194
			foreach ($deletedRecips as $delRecip) {
3195
				$found = false;
3196
3197
				// Search if the deleted recipient can be found inside
3198
				// the updated recipients as well.
3199
				foreach ($modifiedRecips as $recip) {
3200
					if ($this->compareABEntryIDs($recip[PR_ENTRYID], $delRecip[PR_ENTRYID])) {
3201
						$found = true;
3202
						break;
3203
					}
3204
				}
3205
3206
				// If the recipient was not found, it truly is deleted,
3207
				// and we can safely send a cancellation message
3208
				if (!$found) {
3209
					$tmp[] = $delRecip;
3210
				}
3211
			}
3212
3213
			$deletedRecips = $tmp;
3214
		}
3215
3216
		// Send cancellation to deleted attendees
3217
		if ($deletedRecips && !empty($deletedRecips)) {
3218
			$new = $this->createOutgoingMessage();
3219
3220
			mapi_message_modifyrecipients($new, MODRECIP_ADD, $deletedRecips);
3221
3222
			$newmessageprops[PR_MESSAGE_CLASS] = 'IPM.Schedule.Meeting.Canceled';
3223
			$newmessageprops[$this->proptags['meetingstatus']] = olMeetingCanceled; // It's a cancel request
3224
			$newmessageprops[$this->proptags['busystatus']] = fbFree; // set the busy status as free
3225
			$newmessageprops[PR_IMPORTANCE] = IMPORTANCE_HIGH;	// HIGH Importance
3226
			if (isset($newmessageprops[PR_SUBJECT])) {
3227
				$newmessageprops[PR_SUBJECT] = dgettext('zarafa', 'Canceled') . ': ' . $newmessageprops[PR_SUBJECT];
3228
			}
3229
3230
			mapi_setprops($new, $newmessageprops);
3231
			mapi_savechanges($new);
3232
3233
			// Submit message to non-resource recipients
3234
			mapi_message_submitmessage($new);
3235
		}
3236
3237
		// Set properties on meeting object in calendar
3238
		// Set requestsent to 'true' (turns on 'tracking', etc)
3239
		$props = [];
3240
		$props[$this->proptags['meetingstatus']] = olMeeting;
3241
		$props[$this->proptags['responsestatus']] = olResponseOrganized;
3242
		// Only set the 'requestsent' property if it wasn't set previously yet,
3243
		// this ensures we will not accidentally set it from true to false.
3244
		if (!isset($messageprops[$this->proptags['requestsent']]) || $messageprops[$this->proptags['requestsent']] !== true) {
3245
			$props[$this->proptags['requestsent']] = !empty($modifiedRecips) || ($this->includesResources && !$this->errorSetResource);
3246
		}
3247
		$props[$this->proptags['attendee_critical_change']] = time();
3248
		$props[$this->proptags['owner_critical_change']] = time();
3249
		$props[$this->proptags['meetingtype']] = mtgRequest;
3250
		// save the new updatecounter to exception/recurring series/normal meeting
3251
		$props[$this->proptags['updatecounter']] = $newmessageprops[$this->proptags['updatecounter']];
3252
3253
		// PR_START_DATE and PR_END_DATE will be used by outlook to show the position in the calendar
3254
		$props[PR_START_DATE] = $messageprops[$this->proptags['startdate']];
3255
		$props[PR_END_DATE] = $messageprops[$this->proptags['duedate']];
3256
3257
		mapi_setprops($message, $props);
3258
3259
		// saving of these properties on calendar item should be handled by caller function
3260
		// based on sending meeting request was successful or not
3261
	}
3262
3263
	/**
3264
	 * OL2007 uses these 4 properties to specify occurrence that should be updated.
3265
	 * ical generates RECURRENCE-ID property based on exception's basedate (PidLidExceptionReplaceTime),
3266
	 * but OL07 doesn't send this property, so ical will generate RECURRENCE-ID property based on date
3267
	 * from GlobalObjId and time from StartRecurTime property, so we are sending basedate property and
3268
	 * also additionally we are sending these properties.
3269
	 * Ref: MS-OXCICAL 2.2.1.20.20 Property: RECURRENCE-ID.
3270
	 *
3271
	 * @param object $recurObject     instance of recurrence class for this message
3272
	 * @param array  $messageprops    properties of meeting object that is going to be sent
3273
	 * @param array  $newmessageprops properties of meeting request/response that is going to be sent
3274
	 */
3275
	public function generateRecurDates($recurObject, $messageprops, &$newmessageprops): void {
3276
		if ($messageprops[$this->proptags['startdate']] && $messageprops[$this->proptags['duedate']]) {
3277
			$startDate = date('Y:n:j:G:i:s', $recurObject->fromGMT($recurObject->tz, $messageprops[$this->proptags['startdate']]));
3278
			$endDate = date('Y:n:j:G:i:s', $recurObject->fromGMT($recurObject->tz, $messageprops[$this->proptags['duedate']]));
3279
3280
			$startDate = explode(':', $startDate);
3281
			$endDate = explode(':', $endDate);
3282
3283
			// [0] => year, [1] => month, [2] => day, [3] => hour, [4] => minutes, [5] => seconds
3284
			// RecurStartDate = year * 512 + month_number * 32 + day_number
3285
			$newmessageprops[$this->proptags['start_recur_date']] = (((int) $startDate[0]) * 512) + (((int) $startDate[1]) * 32) + ((int) $startDate[2]);
3286
			// RecurStartTime = hour * 4096 + minutes * 64 + seconds
3287
			$newmessageprops[$this->proptags['start_recur_time']] = (((int) $startDate[3]) * 4096) + (((int) $startDate[4]) * 64) + ((int) $startDate[5]);
3288
3289
			$newmessageprops[$this->proptags['end_recur_date']] = (((int) $endDate[0]) * 512) + (((int) $endDate[1]) * 32) + ((int) $endDate[2]);
3290
			$newmessageprops[$this->proptags['end_recur_time']] = (((int) $endDate[3]) * 4096) + (((int) $endDate[4]) * 64) + ((int) $endDate[5]);
3291
		}
3292
	}
3293
3294
	/**
3295
	 * Function will create a new outgoing message that will be used to send meeting mail.
3296
	 *
3297
	 * @param mixed $store (optional) store that is used when creating response, if delegate is creating outgoing mail
3298
	 *                     then this would point to delegate store
3299
	 *
3300
	 * @return resource outgoing mail that is created and can be used for sending it
3301
	 */
3302
	public function createOutgoingMessage($store = false) {
3303
		// get logged in user's store that will be used to send mail, for delegate this will be
3304
		// delegate store
3305
		$userStore = $this->openDefaultStore();
3306
3307
		$sentprops = [];
3308
		$outbox = $this->openDefaultOutbox($userStore);
3309
3310
		$outgoing = mapi_folder_createmessage($outbox);
0 ignored issues
show
The function mapi_folder_createmessage was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

3310
		$outgoing = /** @scrutinizer ignore-call */ mapi_folder_createmessage($outbox);
Loading history...
3311
3312
		// check if $store is set and it is not equal to $defaultStore (means its the delegation case)
3313
		if ($store !== false) {
3314
			$storeProps = mapi_getprops($store, [PR_ENTRYID]);
0 ignored issues
show
The function mapi_getprops was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

3314
			$storeProps = /** @scrutinizer ignore-call */ mapi_getprops($store, [PR_ENTRYID]);
Loading history...
3315
			$userStoreProps = mapi_getprops($userStore, [PR_ENTRYID]);
3316
3317
			// @FIXME use entryid comparison functions here
3318
			if ($storeProps[PR_ENTRYID] !== $userStoreProps[PR_ENTRYID]) {
3319
				// get the delegator properties and set it into outgoing mail
3320
				$delegatorDetails = $this->getOwnerAddress($store, false);
3321
3322
				if (!empty($delegatorDetails)) {
3323
					list($ownername, $owneremailaddr, $owneraddrtype, $ownerentryid, $ownersearchkey) = $delegatorDetails;
3324
					$sentprops[PR_SENT_REPRESENTING_EMAIL_ADDRESS] = $owneremailaddr;
0 ignored issues
show
The constant PR_SENT_REPRESENTING_EMAIL_ADDRESS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
3325
					$sentprops[PR_SENT_REPRESENTING_NAME] = $ownername;
0 ignored issues
show
The constant PR_SENT_REPRESENTING_NAME was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
3326
					$sentprops[PR_SENT_REPRESENTING_ADDRTYPE] = $owneraddrtype;
0 ignored issues
show
The constant PR_SENT_REPRESENTING_ADDRTYPE was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
3327
					$sentprops[PR_SENT_REPRESENTING_ENTRYID] = $ownerentryid;
0 ignored issues
show
The constant PR_SENT_REPRESENTING_ENTRYID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
3328
					$sentprops[PR_SENT_REPRESENTING_SEARCH_KEY] = $ownersearchkey;
0 ignored issues
show
The constant PR_SENT_REPRESENTING_SEARCH_KEY was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
3329
				}
3330
3331
				// get the delegate properties and set it into outgoing mail
3332
				$delegateDetails = $this->getOwnerAddress($userStore, false);
3333
3334
				if (!empty($delegateDetails)) {
3335
					list($ownername, $owneremailaddr, $owneraddrtype, $ownerentryid, $ownersearchkey) = $delegateDetails;
3336
					$sentprops[PR_SENDER_EMAIL_ADDRESS] = $owneremailaddr;
0 ignored issues
show
The constant PR_SENDER_EMAIL_ADDRESS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
3337
					$sentprops[PR_SENDER_NAME] = $ownername;
0 ignored issues
show
The constant PR_SENDER_NAME was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
3338
					$sentprops[PR_SENDER_ADDRTYPE] = $owneraddrtype;
0 ignored issues
show
The constant PR_SENDER_ADDRTYPE was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
3339
					$sentprops[PR_SENDER_ENTRYID] = $ownerentryid;
0 ignored issues
show
The constant PR_SENDER_ENTRYID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
3340
					$sentprops[PR_SENDER_SEARCH_KEY] = $ownersearchkey;
0 ignored issues
show
The constant PR_SENDER_SEARCH_KEY was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
3341
				}
3342
			}
3343
		}
3344
		else {
3345
			// normal user is sending mail, so both set of properties will be same
3346
			$userDetails = $this->getOwnerAddress($userStore);
3347
3348
			if (!empty($userDetails)) {
3349
				list($ownername, $owneremailaddr, $owneraddrtype, $ownerentryid, $ownersearchkey) = $userDetails;
3350
				$sentprops[PR_SENT_REPRESENTING_EMAIL_ADDRESS] = $owneremailaddr;
3351
				$sentprops[PR_SENT_REPRESENTING_NAME] = $ownername;
3352
				$sentprops[PR_SENT_REPRESENTING_ADDRTYPE] = $owneraddrtype;
3353
				$sentprops[PR_SENT_REPRESENTING_ENTRYID] = $ownerentryid;
3354
				$sentprops[PR_SENT_REPRESENTING_SEARCH_KEY] = $ownersearchkey;
3355
3356
				$sentprops[PR_SENDER_EMAIL_ADDRESS] = $owneremailaddr;
3357
				$sentprops[PR_SENDER_NAME] = $ownername;
3358
				$sentprops[PR_SENDER_ADDRTYPE] = $owneraddrtype;
3359
				$sentprops[PR_SENDER_ENTRYID] = $ownerentryid;
3360
				$sentprops[PR_SENDER_SEARCH_KEY] = $ownersearchkey;
3361
			}
3362
		}
3363
3364
		$sentprops[PR_SENTMAIL_ENTRYID] = $this->getDefaultSentmailEntryID($userStore);
0 ignored issues
show
The constant PR_SENTMAIL_ENTRYID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
3365
3366
		mapi_setprops($outgoing, $sentprops);
0 ignored issues
show
The function mapi_setprops was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

3366
		/** @scrutinizer ignore-call */ 
3367
  mapi_setprops($outgoing, $sentprops);
Loading history...
3367
3368
		return $outgoing;
3369
	}
3370
3371
	/**
3372
	 * Function which checks that meeting in attendee's calendar is already updated
3373
	 * and we are checking an old meeting request. This function also will update property
3374
	 * meetingtype to indicate that its out of date meeting request.
3375
	 *
3376
	 * @return bool true if meeting request is outofdate else false if it is new
3377
	 */
3378
	public function isMeetingOutOfDate() {
3379
		$result = false;
3380
3381
		$props = mapi_getprops($this->message, [PR_MESSAGE_CLASS, $this->proptags['goid'], $this->proptags['goid2'], $this->proptags['updatecounter'], $this->proptags['meetingtype'], $this->proptags['owner_critical_change']]);
0 ignored issues
show
The function mapi_getprops was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

3381
		$props = /** @scrutinizer ignore-call */ mapi_getprops($this->message, [PR_MESSAGE_CLASS, $this->proptags['goid'], $this->proptags['goid2'], $this->proptags['updatecounter'], $this->proptags['meetingtype'], $this->proptags['owner_critical_change']]);
Loading history...
The constant PR_MESSAGE_CLASS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
3382
3383
		if (!$this->isMeetingRequest($props[PR_MESSAGE_CLASS])) {
3384
			return $result;
3385
		}
3386
3387
		if (isset($props[$this->proptags['meetingtype']]) && ($props[$this->proptags['meetingtype']] & mtgOutOfDate) == mtgOutOfDate) {
3388
			return true;
3389
		}
3390
3391
		// get the basedate to check for exception
3392
		$basedate = $this->getBasedateFromGlobalID($props[$this->proptags['goid']]);
3393
3394
		$calendarItem = $this->getCorrespondentCalendarItem(true);
3395
3396
		// if basedate is provided and we could not find the item then it could be that we are checking
3397
		// an exception so get the exception and check it
3398
		if ($basedate !== false && $calendarItem !== false) {
3399
			$exception = $this->getExceptionItem($calendarItem, $basedate);
3400
3401
			if ($exception !== false) {
0 ignored issues
show
The condition $exception !== false is always true.
Loading history...
3402
				// we are able to find the exception compare with it
3403
				$calendarItem = $exception;
3404
			}
3405
			// we are not able to find exception, could mean that a significant change has occurred on series
3406
			// and it deleted all exceptions, so compare with series
3407
			// $calendarItem already contains reference to series
3408
		}
3409
3410
		if ($calendarItem !== false) {
3411
			$calendarItemProps = mapi_getprops($calendarItem, [
3412
				$this->proptags['owner_critical_change'],
3413
				$this->proptags['updatecounter'],
3414
			]);
3415
3416
			$updateCounter = (isset($calendarItemProps[$this->proptags['updatecounter']]) && $props[$this->proptags['updatecounter']] < $calendarItemProps[$this->proptags['updatecounter']]);
3417
3418
			$criticalChange = (isset($calendarItemProps[$this->proptags['owner_critical_change']]) && $props[$this->proptags['owner_critical_change']] < $calendarItemProps[$this->proptags['owner_critical_change']]);
3419
3420
			if ($updateCounter || $criticalChange) {
3421
				// meeting request is out of date, set properties to indicate this
3422
				mapi_setprops($this->message, [$this->proptags['meetingtype'] => mtgOutOfDate, PR_ICON_INDEX => 1033]);
0 ignored issues
show
The constant PR_ICON_INDEX was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
The function mapi_setprops was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

3422
				/** @scrutinizer ignore-call */ 
3423
    mapi_setprops($this->message, [$this->proptags['meetingtype'] => mtgOutOfDate, PR_ICON_INDEX => 1033]);
Loading history...
3423
				mapi_savechanges($this->message);
0 ignored issues
show
The function mapi_savechanges was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

3423
				/** @scrutinizer ignore-call */ 
3424
    mapi_savechanges($this->message);
Loading history...
3424
3425
				$result = true;
3426
			}
3427
		}
3428
3429
		return $result;
3430
	}
3431
3432
	/**
3433
	 * Function which checks that if we have received a meeting response for an updated meeting in organizer's calendar.
3434
	 *
3435
	 * @param mixed $basedate basedate of the exception if we want to compare with exception
3436
	 *
3437
	 * @return bool true if meeting request is updated later
3438
	 */
3439
	public function isMeetingUpdated($basedate = false) {
3440
		$result = false;
3441
3442
		$props = mapi_getprops($this->message, [PR_MESSAGE_CLASS, $this->proptags['updatecounter']]);
0 ignored issues
show
The constant PR_MESSAGE_CLASS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
The function mapi_getprops was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

3442
		$props = /** @scrutinizer ignore-call */ mapi_getprops($this->message, [PR_MESSAGE_CLASS, $this->proptags['updatecounter']]);
Loading history...
3443
3444
		if (!$this->isMeetingRequestResponse($props[PR_MESSAGE_CLASS])) {
3445
			return $result;
3446
		}
3447
3448
		$calendarItem = $this->getCorrespondentCalendarItem(true);
3449
3450
		if ($calendarItem !== false) {
3451
			// basedate is provided so open exception
3452
			if ($basedate !== false) {
3453
				$exception = $this->getExceptionItem($calendarItem, $basedate);
3454
3455
				if ($exception !== false) {
0 ignored issues
show
The condition $exception !== false is always true.
Loading history...
3456
					// we are able to find the exception compare with it
3457
					$calendarItem = $exception;
3458
				}
3459
				// we are not able to find exception, could mean that a significant change has occurred on series
3460
				// and it deleted all exceptions, so compare with series
3461
				// $calendarItem already contains reference to series
3462
			}
3463
3464
			if ($calendarItem !== false) {
0 ignored issues
show
The condition $calendarItem !== false is always true.
Loading history...
3465
				$calendarItemProps = mapi_getprops($calendarItem, [$this->proptags['updatecounter']]);
3466
3467
				/*
3468
				 * if(message_counter < appointment_counter) meeting object is newer then meeting response (meeting is updated)
3469
				 * if(message_counter >= appointment_counter) meeting is not updated, do normal processing
3470
				 */
3471
				if (isset($calendarItemProps[$this->proptags['updatecounter']], $props[$this->proptags['updatecounter']])) {
3472
					if ($props[$this->proptags['updatecounter']] < $calendarItemProps[$this->proptags['updatecounter']]) {
3473
						$result = true;
3474
					}
3475
				}
3476
			}
3477
		}
3478
3479
		return $result;
3480
	}
3481
3482
	/**
3483
	 * Checks if there has been any significant changes on appointment/meeting item.
3484
	 * Significant changes be:
3485
	 * 1) startdate has been changed
3486
	 * 2) duedate has been changed OR
3487
	 * 3) recurrence pattern has been created, modified or removed.
3488
	 *
3489
	 * @param mixed $oldProps
3490
	 * @param mixed $basedate
3491
	 * @param mixed $isRecurrenceChanged for change in recurrence pattern.
3492
	 *                                   true means Recurrence pattern has been changed,
3493
	 *                                   so clear all attendees response
3494
	 */
3495
	public function checkSignificantChanges($oldProps, $basedate, $isRecurrenceChanged = false) {
3496
		$message = null;
3497
		$attach = null;
3498
3499
		// If basedate is specified then we need to open exception message to clear recipient responses
3500
		if ($basedate) {
3501
			$recurrence = new Recurrence($this->store, $this->message);
3502
			if ($recurrence->isException($basedate)) {
3503
				$attach = $recurrence->getExceptionAttachment($basedate);
3504
				if ($attach) {
3505
					$message = mapi_attach_openobj($attach, MAPI_MODIFY);
0 ignored issues
show
The function mapi_attach_openobj was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

3505
					$message = /** @scrutinizer ignore-call */ mapi_attach_openobj($attach, MAPI_MODIFY);
Loading history...
3506
				}
3507
			}
3508
		}
3509
		else {
3510
			// use normal message or recurring series message
3511
			$message = $this->message;
3512
		}
3513
3514
		if (!$message) {
3515
			return;
3516
		}
3517
3518
		$newProps = mapi_getprops($message, [$this->proptags['startdate'], $this->proptags['duedate'], $this->proptags['updatecounter']]);
0 ignored issues
show
The function mapi_getprops was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

3518
		$newProps = /** @scrutinizer ignore-call */ mapi_getprops($message, [$this->proptags['startdate'], $this->proptags['duedate'], $this->proptags['updatecounter']]);
Loading history...
3519
3520
		// Check whether message is updated or not.
3521
		if (isset($newProps[$this->proptags['updatecounter']]) && $newProps[$this->proptags['updatecounter']] == 0) {
3522
			return;
3523
		}
3524
3525
		if (($newProps[$this->proptags['startdate']] != $oldProps[$this->proptags['startdate']]) ||
3526
				($newProps[$this->proptags['duedate']] != $oldProps[$this->proptags['duedate']]) ||
3527
				$isRecurrenceChanged) {
3528
			$this->clearRecipientResponse($message);
3529
3530
			mapi_setprops($message, [$this->proptags['owner_critical_change'] => time()]);
0 ignored issues
show
The function mapi_setprops was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

3530
			/** @scrutinizer ignore-call */ 
3531
   mapi_setprops($message, [$this->proptags['owner_critical_change'] => time()]);
Loading history...
3531
3532
			mapi_savechanges($message);
0 ignored issues
show
The function mapi_savechanges was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

3532
			/** @scrutinizer ignore-call */ 
3533
   mapi_savechanges($message);
Loading history...
3533
			if ($attach) { // Also save attachment Object.
3534
				mapi_savechanges($attach);
3535
			}
3536
		}
3537
	}
3538
3539
	/**
3540
	 * Clear responses of all attendees who have replied in past.
3541
	 *
3542
	 * @param resource $message on which responses should be cleared
3543
	 */
3544
	public function clearRecipientResponse($message): void {
3545
		$recipTable = mapi_message_getrecipienttable($message);
0 ignored issues
show
The function mapi_message_getrecipienttable was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

3545
		$recipTable = /** @scrutinizer ignore-call */ mapi_message_getrecipienttable($message);
Loading history...
3546
		$recipsRows = mapi_table_queryallrows($recipTable, $this->recipprops);
0 ignored issues
show
The function mapi_table_queryallrows was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

3546
		$recipsRows = /** @scrutinizer ignore-call */ mapi_table_queryallrows($recipTable, $this->recipprops);
Loading history...
3547
3548
		foreach ($recipsRows as $recipient) {
3549
			if (($recipient[PR_RECIPIENT_FLAGS] & recipOrganizer) != recipOrganizer) {
0 ignored issues
show
The constant PR_RECIPIENT_FLAGS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
3550
				// Recipient is attendee, set the trackstatus to 'Not Responded'
3551
				$recipient[PR_RECIPIENT_TRACKSTATUS] = olRecipientTrackStatusNone;
0 ignored issues
show
The constant PR_RECIPIENT_TRACKSTATUS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
3552
			}
3553
			else {
3554
				// Recipient is organizer, this is not possible, but for safety
3555
				// it is best to clear the trackstatus for him as well by setting
3556
				// the trackstatus to 'Organized'.
3557
				$recipient[PR_RECIPIENT_TRACKSTATUS] = olRecipientTrackStatusNone;
3558
			}
3559
			mapi_message_modifyrecipients($message, MODRECIP_MODIFY, [$recipient]);
0 ignored issues
show
The function mapi_message_modifyrecipients was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

3559
			/** @scrutinizer ignore-call */ 
3560
   mapi_message_modifyrecipients($message, MODRECIP_MODIFY, [$recipient]);
Loading history...
3560
		}
3561
	}
3562
3563
	/**
3564
	 * Function returns correspondent calendar item attached with the meeting request/response/cancellation.
3565
	 * This will only check for actual MAPIMessages in calendar folder, so if a meeting request is
3566
	 * for exception then this function will return recurring series for that meeting request
3567
	 * after that you need to use getExceptionItem function to get exception item that will be
3568
	 * fetched from the attachment table of recurring series MAPIMessage.
3569
	 *
3570
	 * @param bool $open boolean to indicate the function should return entryid or MAPIMessage. Defaults to true.
3571
	 *
3572
	 * @return bool|resource resource of calendar item
3573
	 */
3574
	public function getCorrespondentCalendarItem($open = true) {
3575
		$props = mapi_getprops($this->message, [PR_MESSAGE_CLASS, $this->proptags['goid'], $this->proptags['goid2'], PR_RCVD_REPRESENTING_ENTRYID]);
0 ignored issues
show
The constant PR_MESSAGE_CLASS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
The function mapi_getprops was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

3575
		$props = /** @scrutinizer ignore-call */ mapi_getprops($this->message, [PR_MESSAGE_CLASS, $this->proptags['goid'], $this->proptags['goid2'], PR_RCVD_REPRESENTING_ENTRYID]);
Loading history...
The constant PR_RCVD_REPRESENTING_ENTRYID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
3576
3577
		if (!$this->isMeetingRequest($props[PR_MESSAGE_CLASS]) && !$this->isMeetingRequestResponse($props[PR_MESSAGE_CLASS]) && !$this->isMeetingCancellation($props[PR_MESSAGE_CLASS])) {
3578
			// can work only with meeting requests/responses/cancellations
3579
			return false;
3580
		}
3581
3582
		$globalId = $props[$this->proptags['goid']];
3583
		$cleanGlobalId = $props[$this->proptags['goid2']];
3584
3585
		// If Delegate is processing Meeting Request/Response for Delegator then retrieve Delegator's store and calendar.
3586
		if (isset($props[PR_RCVD_REPRESENTING_ENTRYID])) {
3587
			$delegatorStore = $this->getDelegatorStore($props[PR_RCVD_REPRESENTING_ENTRYID], [PR_IPM_APPOINTMENT_ENTRYID]);
0 ignored issues
show
The constant PR_IPM_APPOINTMENT_ENTRYID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
3588
3589
			$store = $delegatorStore['store'];
3590
			$calFolder = $delegatorStore[PR_IPM_APPOINTMENT_ENTRYID];
3591
		}
3592
		else {
3593
			$store = $this->store;
3594
			$calFolder = $this->openDefaultCalendar();
3595
		}
3596
3597
		$basedate = $this->getBasedateFromGlobalID($globalId);
3598
3599
		/**
3600
		 * First search for any appointments which correspond to the $globalId,
3601
		 * this can be the entire series (if the Meeting Request refers to the
3602
		 * entire series), or an particular Occurrence (if the meeting Request
3603
		 * contains a basedate).
3604
		 *
3605
		 * If we cannot find a corresponding item, and the $globalId contains
3606
		 * a $basedate, it might imply that a new exception will have to be
3607
		 * created for a series which is present in the calendar, we can look
3608
		 * that one up by searching for the $cleanGlobalId.
3609
		 */
3610
		$entryids = $this->findCalendarItems($globalId, $calFolder);
3611
		if ($basedate !== false && empty($entryids)) {
3612
			$entryids = $this->findCalendarItems($cleanGlobalId, $calFolder, true);
3613
		}
3614
3615
		// there should be only one item returned
3616
		if (!empty($entryids) && count($entryids) === 1) {
3617
			// return only entryid
3618
			if ($open === false) {
3619
				return $entryids[0];
3620
			}
3621
3622
			// open calendar item and return it
3623
			return mapi_msgstore_openentry($store, $entryids[0]);
0 ignored issues
show
The function mapi_msgstore_openentry was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

3623
			return /** @scrutinizer ignore-call */ mapi_msgstore_openentry($store, $entryids[0]);
Loading history...
3624
		}
3625
3626
		// no items found in calendar
3627
		return false;
3628
	}
3629
3630
	/**
3631
	 * Function returns exception item based on the basedate passed.
3632
	 *
3633
	 * @param mixed $recurringMessage Resource of Recurring meeting from calendar
3634
	 * @param mixed $basedate         basedate of exception that needs to be returned
3635
	 * @param mixed $store            store that contains the recurring calendar item
3636
	 *
3637
	 * @return entryid or MAPIMessage resource of exception item
0 ignored issues
show
The type entryid was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
3638
	 */
3639
	public function getExceptionItem($recurringMessage, $basedate, $store = false) {
3640
		$occurItem = false;
3641
3642
		$props = mapi_getprops($this->message, [PR_RCVD_REPRESENTING_ENTRYID, $this->proptags['recurring']]);
0 ignored issues
show
The function mapi_getprops was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

3642
		$props = /** @scrutinizer ignore-call */ mapi_getprops($this->message, [PR_RCVD_REPRESENTING_ENTRYID, $this->proptags['recurring']]);
Loading history...
The constant PR_RCVD_REPRESENTING_ENTRYID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
3643
3644
		// check if the passed item is recurring series
3645
		if (isset($props[$this->proptags['recurring']]) && $props[$this->proptags['recurring']] !== false) {
3646
			return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type entryid.
Loading history...
3647
		}
3648
3649
		if ($store === false) {
3650
			// If Delegate is processing Meeting Request/Response for Delegator then retrieve Delegator's store and calendar.
3651
			if (isset($props[PR_RCVD_REPRESENTING_ENTRYID])) {
3652
				$delegatorStore = $this->getDelegatorStore($props[PR_RCVD_REPRESENTING_ENTRYID]);
3653
				$store = $delegatorStore['store'];
3654
			}
3655
			else {
3656
				$store = $this->store;
3657
			}
3658
		}
3659
3660
		$recurr = new Recurrence($store, $recurringMessage);
3661
		$attach = $recurr->getExceptionAttachment($basedate);
3662
		if ($attach) {
3663
			$occurItem = mapi_attach_openobj($attach);
0 ignored issues
show
The function mapi_attach_openobj was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

3663
			$occurItem = /** @scrutinizer ignore-call */ mapi_attach_openobj($attach);
Loading history...
3664
		}
3665
3666
		return $occurItem;
3667
	}
3668
3669
	/**
3670
	 * Function which checks whether received meeting request is either conflicting with other appointments or not.
3671
	 *
3672
	 * @param false|resource $message
3673
	 * @param false|resource $userStore
3674
	 * @param mixed          $calFolder calendar folder for conflict checking
3675
	 *
3676
	 * @return bool|int
3677
	 *
3678
	 * @psalm-return bool|int<1, max>
3679
	 */
3680
	public function isMeetingConflicting($message = false, $userStore = false, $calFolder = false) {
3681
		$returnValue = false;
3682
		$noOfInstances = 0;
3683
3684
		if ($message === false) {
3685
			$message = $this->message;
3686
		}
3687
3688
		$messageProps = mapi_getprops(
0 ignored issues
show
The function mapi_getprops was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

3688
		$messageProps = /** @scrutinizer ignore-call */ mapi_getprops(
Loading history...
3689
			$message,
3690
			[
3691
				PR_MESSAGE_CLASS,
0 ignored issues
show
The constant PR_MESSAGE_CLASS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
3692
				$this->proptags['goid'],
3693
				$this->proptags['goid2'],
3694
				$this->proptags['startdate'],
3695
				$this->proptags['duedate'],
3696
				$this->proptags['recurring'],
3697
				$this->proptags['clipstart'],
3698
				$this->proptags['clipend'],
3699
				PR_RCVD_REPRESENTING_ENTRYID,
0 ignored issues
show
The constant PR_RCVD_REPRESENTING_ENTRYID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
3700
				$this->proptags['basedate'],
3701
				PR_RCVD_REPRESENTING_NAME,
0 ignored issues
show
The constant PR_RCVD_REPRESENTING_NAME was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
3702
			]
3703
		);
3704
3705
		if ($userStore === false) {
3706
			$userStore = $this->store;
3707
3708
			// check if delegate is processing the response
3709
			if (isset($messageProps[PR_RCVD_REPRESENTING_ENTRYID])) {
3710
				$delegatorStore = $this->getDelegatorStore($messageProps[PR_RCVD_REPRESENTING_ENTRYID], [PR_IPM_APPOINTMENT_ENTRYID]);
0 ignored issues
show
The constant PR_IPM_APPOINTMENT_ENTRYID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
3711
3712
				$userStore = $delegatorStore['store'];
3713
				$calFolder = $delegatorStore[PR_IPM_APPOINTMENT_ENTRYID];
3714
			}
3715
		}
3716
3717
		if ($calFolder === false) {
3718
			$calFolder = $this->openDefaultCalendar($userStore);
3719
		}
3720
3721
		if ($calFolder) {
3722
			// Meeting request is recurring, so get all occurrence and check for each occurrence whether it conflicts with other appointments in Calendar.
3723
			if (isset($messageProps[$this->proptags['recurring']]) && $messageProps[$this->proptags['recurring']] === true) {
3724
				// Apply recurrence class and retrieve all occurrences(max: 30 occurrence because recurrence can also be set as 'no end date')
3725
				$recurr = new Recurrence($userStore, $message);
3726
				$items = $recurr->getItems($messageProps[$this->proptags['clipstart']], $messageProps[$this->proptags['clipend']] * (24 * 24 * 60), 30);
3727
3728
				foreach ($items as $item) {
3729
					// Get all items in the timeframe that we want to book, and get the goid and busystatus for each item
3730
					$calendarItems = $recurr->getCalendarItems($userStore, $calFolder, $item[$this->proptags['startdate']], $item[$this->proptags['duedate']], [$this->proptags['goid'], $this->proptags['busystatus']]);
3731
3732
					foreach ($calendarItems as $calendarItem) {
3733
						if ($calendarItem[$this->proptags['busystatus']] !== fbFree) {
3734
							/*
3735
							 * Only meeting requests have globalID, normal appointments do not have globalID
3736
							 * so if any normal appointment if found then it is assumed to be conflict.
3737
							 */
3738
							if (isset($calendarItem[$this->proptags['goid']])) {
3739
								if ($calendarItem[$this->proptags['goid']] !== $messageProps[$this->proptags['goid']]) {
3740
									++$noOfInstances;
3741
									break;
3742
								}
3743
							}
3744
							else {
3745
								++$noOfInstances;
3746
								break;
3747
							}
3748
						}
3749
					}
3750
				}
3751
3752
				if ($noOfInstances > 0) {
3753
					$returnValue = $noOfInstances;
3754
				}
3755
			}
3756
			else {
3757
				// Get all items in the timeframe that we want to book, and get the goid and busystatus for each item
3758
				$items = getCalendarItems($userStore, $calFolder, $messageProps[$this->proptags['startdate']], $messageProps[$this->proptags['duedate']], [$this->proptags['goid'], $this->proptags['busystatus']]);
3759
3760
				if (isset($messageProps[$this->proptags['basedate']]) && !empty($messageProps[$this->proptags['basedate']])) {
3761
					$basedate = $messageProps[$this->proptags['basedate']];
3762
					// Get the goid2 from recurring MR which further used to
3763
					// check the resource conflicts item.
3764
					$recurrItemProps = mapi_getprops($this->message, [$this->proptags['goid2']]);
3765
					$messageProps[$this->proptags['goid']] = $this->setBasedateInGlobalID($recurrItemProps[$this->proptags['goid2']], $basedate);
3766
					$messageProps[$this->proptags['goid2']] = $recurrItemProps[$this->proptags['goid2']];
3767
				}
3768
3769
				foreach ($items as $item) {
3770
					if ($item[$this->proptags['busystatus']] !== fbFree) {
3771
						if (isset($item[$this->proptags['goid']])) {
3772
							if (($item[$this->proptags['goid']] !== $messageProps[$this->proptags['goid']]) &&
3773
								($item[$this->proptags['goid']] !== $messageProps[$this->proptags['goid2']])) {
3774
								$returnValue = true;
3775
								break;
3776
							}
3777
						}
3778
						else {
3779
							$returnValue = true;
3780
							break;
3781
						}
3782
					}
3783
				}
3784
			}
3785
		}
3786
3787
		return $returnValue;
3788
	}
3789
3790
	/**
3791
	 * Function which adds organizer to recipient list which is passed.
3792
	 * This function also checks if it has organizer.
3793
	 *
3794
	 * @param array $messageProps message properties
3795
	 * @param array $recipients   recipients list of message
3796
	 */
3797
	public function addDelegator($messageProps, &$recipients): void {
3798
		$hasDelegator = false;
3799
		// Check if meeting already has an organizer.
3800
		foreach ($recipients as $key => $recipient) {
3801
			if (isset($messageProps[PR_RCVD_REPRESENTING_EMAIL_ADDRESS]) && $recipient[PR_EMAIL_ADDRESS] == $messageProps[PR_RCVD_REPRESENTING_EMAIL_ADDRESS]) {
0 ignored issues
show
The constant PR_RCVD_REPRESENTING_EMAIL_ADDRESS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
The constant PR_EMAIL_ADDRESS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
3802
				$hasDelegator = true;
3803
			}
3804
		}
3805
3806
		if (!$hasDelegator) {
3807
			// Create delegator.
3808
			$delegator = [];
3809
			$delegator[PR_ENTRYID] = $messageProps[PR_RCVD_REPRESENTING_ENTRYID];
0 ignored issues
show
The constant PR_RCVD_REPRESENTING_ENTRYID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
3810
			$delegator[PR_DISPLAY_NAME] = $messageProps[PR_RCVD_REPRESENTING_NAME];
0 ignored issues
show
The constant PR_DISPLAY_NAME was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
The constant PR_RCVD_REPRESENTING_NAME was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
3811
			$delegator[PR_EMAIL_ADDRESS] = $messageProps[PR_RCVD_REPRESENTING_EMAIL_ADDRESS];
3812
			$delegator[PR_RECIPIENT_TYPE] = MAPI_TO;
0 ignored issues
show
The constant PR_RECIPIENT_TYPE was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
3813
			$delegator[PR_RECIPIENT_DISPLAY_NAME] = $messageProps[PR_RCVD_REPRESENTING_NAME];
0 ignored issues
show
The constant PR_RECIPIENT_DISPLAY_NAME was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
3814
			$delegator[PR_ADDRTYPE] = empty($messageProps[PR_RCVD_REPRESENTING_ADDRTYPE]) ? 'SMTP' : $messageProps[PR_RCVD_REPRESENTING_ADDRTYPE];
0 ignored issues
show
The constant PR_ADDRTYPE was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
The constant PR_RCVD_REPRESENTING_ADDRTYPE was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
3815
			$delegator[PR_RECIPIENT_TRACKSTATUS] = olRecipientTrackStatusNone;
0 ignored issues
show
The constant PR_RECIPIENT_TRACKSTATUS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
3816
			$delegator[PR_RECIPIENT_FLAGS] = recipSendable;
0 ignored issues
show
The constant PR_RECIPIENT_FLAGS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
3817
			$delegator[PR_SEARCH_KEY] = $messageProps[PR_RCVD_REPRESENTING_SEARCH_KEY];
0 ignored issues
show
The constant PR_RCVD_REPRESENTING_SEARCH_KEY was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
The constant PR_SEARCH_KEY was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
3818
3819
			// Add organizer to recipients list.
3820
			array_unshift($recipients, $delegator);
3821
		}
3822
	}
3823
3824
	/**
3825
	 * Function will return delegator's store and calendar folder for processing meetings.
3826
	 *
3827
	 * @param string $receivedRepresentingEntryId entryid of the delegator user
3828
	 * @param array  $foldersToOpen               contains list of folder types that should be returned in result
3829
	 *
3830
	 * @return resource[] contains store of the delegator and resource of folders if $foldersToOpen is not empty
3831
	 *
3832
	 * @psalm-return array<resource>
3833
	 */
3834
	public function getDelegatorStore($receivedRepresentingEntryId, $foldersToOpen = []): array {
3835
		$returnData = [];
3836
3837
		$delegatorStore = $this->openCustomUserStore($receivedRepresentingEntryId);
3838
		$returnData['store'] = $delegatorStore;
3839
3840
		if (!empty($foldersToOpen)) {
3841
			for ($index = 0, $len = count($foldersToOpen); $index < $len; ++$index) {
3842
				$folderType = $foldersToOpen[$index];
3843
3844
				// first try with default folders
3845
				$folder = $this->openDefaultFolder($folderType, $delegatorStore);
3846
3847
				// if folder not found then try with base folders
3848
				if ($folder === false) {
3849
					$folder = $this->openBaseFolder($folderType, $delegatorStore);
3850
				}
3851
3852
				if ($folder === false) {
3853
					// we are still not able to get the folder so give up
3854
					continue;
3855
				}
3856
3857
				$returnData[$folderType] = $folder;
3858
			}
3859
		}
3860
3861
		return $returnData;
3862
	}
3863
3864
	/**
3865
	 * Function returns extra info about meeting timing along with message body
3866
	 * which will be included in body while sending meeting request/response.
3867
	 *
3868
	 * @return false|string $meetingTimeInfo info about meeting timing along with message body
3869
	 */
3870
	public function getMeetingTimeInfo() {
3871
		return $this->meetingTimeInfo;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->meetingTimeInfo also could return the type boolean which is incompatible with the documented return type false|string.
Loading history...
3872
	}
3873
3874
	/**
3875
	 * Function sets extra info about meeting timing along with message body
3876
	 * which will be included in body while sending meeting request/response.
3877
	 *
3878
	 * @param string $meetingTimeInfo info about meeting timing along with message body
3879
	 */
3880
	public function setMeetingTimeInfo($meetingTimeInfo): void {
3881
		$this->meetingTimeInfo = $meetingTimeInfo;
3882
	}
3883
3884
	/**
3885
	 * Helper function which is use to get local categories of all occurrence.
3886
	 *
3887
	 * @param mixed $calendarItem meeting request item
3888
	 * @param mixed $store        store containing calendar folder
3889
	 * @param mixed $calFolder    calendar folder
3890
	 *
3891
	 * @return array $localCategories which contain array of basedate along with categories
3892
	 */
3893
	public function getLocalCategories($calendarItem, $store, $calFolder) {
3894
		$calendarItemProps = mapi_getprops($calendarItem);
0 ignored issues
show
The function mapi_getprops was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

3894
		$calendarItemProps = /** @scrutinizer ignore-call */ mapi_getprops($calendarItem);
Loading history...
3895
		$recurrence = new Recurrence($store, $calendarItem);
3896
3897
		// Retrieve all occurrences(max: 30 occurrence because recurrence can also be set as 'no end date')
3898
		$items = $recurrence->getItems($calendarItemProps[$this->proptags['clipstart']], $calendarItemProps[$this->proptags['clipend']] * (24 * 24 * 60), 30);
3899
		$localCategories = [];
3900
3901
		foreach ($items as $item) {
3902
			$recurrenceItems = $recurrence->getCalendarItems($store, $calFolder, $item[$this->proptags['startdate']], $item[$this->proptags['duedate']], [$this->proptags['goid'], $this->proptags['busystatus'], $this->proptags['categories']]);
3903
			foreach ($recurrenceItems as $recurrenceItem) {
3904
				// Check if occurrence is exception then get the local categories of that occurrence.
3905
				if (isset($recurrenceItem[$this->proptags['goid']]) && $recurrenceItem[$this->proptags['goid']] == $calendarItemProps[$this->proptags['goid']]) {
3906
					$exceptionAttach = $recurrence->getExceptionAttachment($recurrenceItem['basedate']);
3907
3908
					if ($exceptionAttach) {
3909
						$exception = mapi_attach_openobj($exceptionAttach, 0);
0 ignored issues
show
The function mapi_attach_openobj was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

3909
						$exception = /** @scrutinizer ignore-call */ mapi_attach_openobj($exceptionAttach, 0);
Loading history...
3910
						$exceptionProps = mapi_getprops($exception, [$this->proptags['categories']]);
3911
						if (isset($exceptionProps[$this->proptags['categories']])) {
3912
							$localCategories[$recurrenceItem['basedate']] = $exceptionProps[$this->proptags['categories']];
3913
						}
3914
					}
3915
				}
3916
			}
3917
		}
3918
3919
		return $localCategories;
3920
	}
3921
3922
	/**
3923
	 * Helper function which is use to apply local categories on respective occurrences.
3924
	 *
3925
	 * @param mixed $calendarItem    meeting request item
3926
	 * @param mixed $store           store containing calendar folder
3927
	 * @param array $localCategories array contains basedate and array of categories
3928
	 */
3929
	public function applyLocalCategories($calendarItem, $store, $localCategories): void {
3930
		$calendarItemProps = mapi_getprops($calendarItem, [PR_PARENT_ENTRYID, PR_ENTRYID]);
0 ignored issues
show
The constant PR_PARENT_ENTRYID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
The function mapi_getprops was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

3930
		$calendarItemProps = /** @scrutinizer ignore-call */ mapi_getprops($calendarItem, [PR_PARENT_ENTRYID, PR_ENTRYID]);
Loading history...
3931
		$message = mapi_msgstore_openentry($store, $calendarItemProps[PR_ENTRYID]);
0 ignored issues
show
The function mapi_msgstore_openentry was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

3931
		$message = /** @scrutinizer ignore-call */ mapi_msgstore_openentry($store, $calendarItemProps[PR_ENTRYID]);
Loading history...
3932
		$recurrence = new Recurrence($store, $message);
3933
3934
		// Check for all occurrence if it is exception then modify the exception by setting up categories,
3935
		// Otherwise create new exception with categories.
3936
		foreach ($localCategories as $key => $value) {
3937
			if ($recurrence->isException($key)) {
3938
				$recurrence->modifyException([$this->proptags['categories'] => $value], $key);
3939
			}
3940
			else {
3941
				$recurrence->createException([$this->proptags['categories'] => $value], $key, false);
3942
			}
3943
			mapi_savechanges($message);
0 ignored issues
show
The function mapi_savechanges was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

3943
			/** @scrutinizer ignore-call */ 
3944
   mapi_savechanges($message);
Loading history...
3944
		}
3945
	}
3946
}
3947