Passed
Push — master ( fa4c11...18b40f )
by
unknown
12:20 queued 13s
created

class.meetingrequest.php (430 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
		PR_SMTP_ADDRESS,
0 ignored issues
show
The constant PR_SMTP_ADDRESS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
96
	];
97
98
	/**
99
	 * Indication whether the setting of resources in a Meeting Request is success (false) or if it
100
	 * has failed (integer).
101
	 *
102
	 * @var null|false|int
103
	 *
104
	 * @psalm-var 1|3|4|false|null
105
	 */
106
	public $errorSetResource;
107
108
	public $proptags;
109
	private $store;
110
	public $message;
111
	private $session;
112
113
	/**
114
	 * @var false|string
115
	 */
116
	private $meetingTimeInfo;
117
	private $enableDirectBooking;
118
119
	/**
120
	 * @var null|bool
121
	 */
122
	private $includesResources;
123
	private $nonAcceptingResources;
124
	private $recipientDisplayname;
125
126
	/**
127
	 * Constructor.
128
	 *
129
	 * Takes a store and a message. The message is an appointment item
130
	 * that should be converted into a meeting request or an incoming
131
	 * e-mail message that is a meeting request.
132
	 *
133
	 * The $session variable is optional, but required if the following features
134
	 * are to be used:
135
	 *
136
	 * - Sending meeting requests for meetings that are not in your own store
137
	 * - Sending meeting requests to resources, resource availability checking and resource freebusy updates
138
	 *
139
	 * @param mixed $store
140
	 * @param mixed $message
141
	 * @param mixed $session
142
	 * @param mixed $enableDirectBooking
143
	 */
144
	public function __construct($store, $message, $session = false, $enableDirectBooking = true) {
145
		$this->store = $store;
146
		$this->message = $message;
147
		$this->session = $session;
148
		// This variable string saves time information for the MR.
149
		$this->meetingTimeInfo = false;
150
		$this->enableDirectBooking = $enableDirectBooking;
151
152
		$properties = [];
153
		$properties['goid'] = 'PT_BINARY:PSETID_Meeting:0x3';
154
		$properties['goid2'] = 'PT_BINARY:PSETID_Meeting:0x23';
155
		$properties['type'] = 'PT_STRING8:PSETID_Meeting:0x24';
156
		$properties['meetingrecurring'] = 'PT_BOOLEAN:PSETID_Meeting:0x5';
157
		$properties['unknown2'] = 'PT_BOOLEAN:PSETID_Meeting:0xa';
158
		$properties['attendee_critical_change'] = 'PT_SYSTIME:PSETID_Meeting:0x1';
159
		$properties['owner_critical_change'] = 'PT_SYSTIME:PSETID_Meeting:0x1a';
160
		$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...
161
		$properties['responsestatus'] = 'PT_LONG:PSETID_Appointment:0x8218';
162
		$properties['unknown6'] = 'PT_LONG:PSETID_Meeting:0x4';
163
		$properties['replytime'] = 'PT_SYSTIME:PSETID_Appointment:0x8220';
164
		$properties['usetnef'] = 'PT_BOOLEAN:PSETID_Common:0x8582';
165
		$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...
166
		$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...
167
		$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...
168
		$properties['sendasical'] = 'PT_BOOLEAN:PSETID_Appointment:0x8200';
169
		$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...
170
		$properties['unknown7'] = 'PT_LONG:PSETID_Appointment:0x8202';
171
		$properties['last_updatecounter'] = 'PT_LONG:PSETID_Appointment:0x8203';			// AppointmentLastSequence
172
		$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...
173
		$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...
174
		$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...
175
		$properties['responselocation'] = 'PT_STRING8:PSETID_Meeting:0x2';
176
		$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...
177
		$properties['requestsent'] = 'PT_BOOLEAN:PSETID_Appointment:0x8229';		// PidLidFInvited, MeetingRequestWasSent
178
		$properties['startdate'] = 'PT_SYSTIME:PSETID_Appointment:' . PidLidAppointmentStartWhole;
179
		$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...
180
		$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...
181
		$properties['commonstart'] = 'PT_SYSTIME:PSETID_Common:0x8516';
182
		$properties['commonend'] = 'PT_SYSTIME:PSETID_Common:0x8517';
183
		$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...
184
		$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...
185
		$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...
186
		$properties['start_recur_date'] = 'PT_LONG:PSETID_Meeting:0xD';				// StartRecurTime
187
		$properties['start_recur_time'] = 'PT_LONG:PSETID_Meeting:0xE';				// StartRecurTime
188
		$properties['end_recur_date'] = 'PT_LONG:PSETID_Meeting:0xF';				// EndRecurDate
189
		$properties['end_recur_time'] = 'PT_LONG:PSETID_Meeting:0x10';				// EndRecurTime
190
		$properties['is_exception'] = 'PT_BOOLEAN:PSETID_Meeting:0xA';				// LID_IS_EXCEPTION
191
		$properties['apptreplyname'] = 'PT_STRING8:PSETID_Appointment:0x8230';
192
		// Propose new time properties
193
		$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...
194
		$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...
195
		$properties['proposed_duration'] = 'PT_LONG:PSETID_Appointment:0x8256';
196
		$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...
197
		$properties['recurring_pattern'] = 'PT_STRING8:PSETID_Appointment:0x8232';
198
		$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...
199
		$properties['meetingtype'] = 'PT_LONG:PSETID_Meeting:0x26';
200
		$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...
201
		$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...
202
		$properties['categories'] = 'PT_MV_STRING8:PS_PUBLIC_STRINGS:Keywords';
203
		$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...
204
		$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...
205
		$properties['toattendeesstring'] = 'PT_STRING8:PSETID_Appointment:0x823B';
206
		$properties['ccattendeesstring'] = 'PT_STRING8:PSETID_Appointment:0x823C';
207
208
		$this->proptags = getPropIdsFromStrings($store, $properties);
209
	}
210
211
	/**
212
	 * Sets the direct booking property. This is an alternative to the setting of the direct booking
213
	 * property through the constructor. However, setting it in the constructor is preferred.
214
	 *
215
	 * @param bool $directBookingSetting
216
	 */
217
	public function setDirectBooking($directBookingSetting): void {
218
		$this->enableDirectBooking = $directBookingSetting;
219
	}
220
221
	/**
222
	 * Returns TRUE if the message pointed to is an incoming meeting request and should
223
	 * therefore be replied to with doAccept or doDecline().
224
	 *
225
	 * @param string $messageClass message class to use for checking
226
	 *
227
	 * @return bool returns true if this is a meeting request else false
228
	 */
229
	public function isMeetingRequest($messageClass = false) {
230
		if ($messageClass === false) {
231
			$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

231
			$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...
232
			$messageClass = isset($props[PR_MESSAGE_CLASS]) ? $props[PR_MESSAGE_CLASS] : false;
233
		}
234
235
		if ($messageClass !== false && stripos($messageClass, 'ipm.schedule.meeting.request') === 0) {
236
			return true;
237
		}
238
239
		return false;
240
	}
241
242
	/**
243
	 * Returns TRUE if the message pointed to is a returning meeting request response.
244
	 *
245
	 * @param string $messageClass message class to use for checking
246
	 *
247
	 * @return bool returns true if this is a meeting request else false
248
	 */
249
	public function isMeetingRequestResponse($messageClass = false) {
250
		if ($messageClass === false) {
251
			$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

251
			$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...
252
			$messageClass = isset($props[PR_MESSAGE_CLASS]) ? $props[PR_MESSAGE_CLASS] : false;
253
		}
254
255
		if ($messageClass !== false && stripos($messageClass, 'ipm.schedule.meeting.resp') === 0) {
256
			return true;
257
		}
258
259
		return false;
260
	}
261
262
	/**
263
	 * Returns TRUE if the message pointed to is a cancellation request.
264
	 *
265
	 * @param string $messageClass message class to use for checking
266
	 *
267
	 * @return bool returns true if this is a meeting request else false
268
	 */
269
	public function isMeetingCancellation($messageClass = false) {
270
		if ($messageClass === false) {
271
			$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

271
			$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...
272
			$messageClass = isset($props[PR_MESSAGE_CLASS]) ? $props[PR_MESSAGE_CLASS] : false;
273
		}
274
275
		if ($messageClass !== false && stripos($messageClass, 'ipm.schedule.meeting.canceled') === 0) {
276
			return true;
277
		}
278
279
		return false;
280
	}
281
282
	/**
283
	 * Function is used to get the last update counter of meeting request.
284
	 *
285
	 * @return bool|int false when last_updatecounter not found else return last_updatecounter
286
	 */
287
	public function getLastUpdateCounter() {
288
		$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

288
		$calendarItemProps = /** @scrutinizer ignore-call */ mapi_getprops($this->message, [$this->proptags['last_updatecounter']]);
Loading history...
289
		if (isset($calendarItemProps) && !empty($calendarItemProps)) {
290
			return $calendarItemProps[$this->proptags['last_updatecounter']];
291
		}
292
293
		return false;
294
	}
295
296
	/**
297
	 * Process an incoming meeting request response. This updates the appointment
298
	 * in your calendar to show whether the user has accepted or declined.
299
	 */
300
	public function processMeetingRequestResponse() {
301
		if (!$this->isMeetingRequestResponse()) {
302
			return;
303
		}
304
305
		if (!$this->isLocalOrganiser()) {
306
			return;
307
		}
308
309
		// Get information we need from the response message
310
		$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

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

382
		$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_PARENT_ENTRYID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
383
384
		// check if meeting response is already processed
385
		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...
386
			// meeting is already processed
387
			return;
388
		}
389
		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

389
		/** @scrutinizer ignore-call */ 
390
  mapi_setprops($this->message, [PR_PROCESSED => true]);
Loading history...
390
		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

390
		/** @scrutinizer ignore-call */ 
391
  mapi_savechanges($this->message);
Loading history...
391
392
		// if meeting is updated in organizer's calendar then we don't need to process
393
		// old response
394
		if ($this->isMeetingUpdated($basedate)) {
395
			return;
396
		}
397
398
		// If basedate is found, then create/modify exception msg and do processing
399
		if ($basedate && isset($calendarItemProps[$this->proptags['recurring']]) && $calendarItemProps[$this->proptags['recurring']] === true) {
400
			$recurr = new Recurrence($store, $calendarItem);
401
402
			// Copy properties from meeting request
403
			$exception_props = mapi_getprops($this->message, [
404
				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...
405
				$this->proptags['proposed_start_whole'],
406
				$this->proptags['proposed_end_whole'],
407
				$this->proptags['proposed_duration'],
408
				$this->proptags['counter_proposal'],
409
			]);
410
411
			// Create/modify exception
412
			if ($recurr->isException($basedate)) {
413
				$recurr->modifyException($exception_props, $basedate);
414
			}
415
			else {
416
				// When we are creating an exception we need copy recipients from main recurring item
417
				$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

417
				$recipTable = /** @scrutinizer ignore-call */ mapi_message_getrecipienttable($calendarItem);
Loading history...
418
				$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

418
				$recips = /** @scrutinizer ignore-call */ mapi_table_queryallrows($recipTable, $this->recipprops);
Loading history...
419
420
				// Retrieve actual start/due dates from calendar item.
421
				$exception_props[$this->proptags['startdate']] = $recurr->getOccurrenceStart($basedate);
422
				$exception_props[$this->proptags['duedate']] = $recurr->getOccurrenceEnd($basedate);
423
424
				$recurr->createException($exception_props, $basedate, false, $recips);
425
			}
426
427
			mapi_savechanges($calendarItem);
428
429
			$attach = $recurr->getExceptionAttachment($basedate);
430
			if ($attach) {
431
				$recurringItem = $calendarItem;
432
				$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

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

477
				/** @scrutinizer ignore-call */ 
478
    mapi_message_modifyrecipients($calendarItem, MODRECIP_REMOVE, [$recipient]);
Loading history...
478
				mapi_message_modifyrecipients($calendarItem, MODRECIP_ADD, [$recipient]);
479
			}
480
			if (isset($recipient[PR_RECIPIENT_TRACKSTATUS]) && $recipient[PR_RECIPIENT_TRACKSTATUS] == olRecipientTrackStatusAccepted) {
481
				++$acceptedrecips;
482
			}
483
		}
484
485
		// If the recipient was not found in the original calendar item,
486
		// then add the recpient as a new optional recipient
487
		if (!$found) {
488
			$recipient = [];
489
			$recipient[PR_ENTRYID] = $messageprops[PR_SENT_REPRESENTING_ENTRYID];
490
			$recipient[PR_EMAIL_ADDRESS] = $messageprops[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...
The constant PR_EMAIL_ADDRESS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
491
			$recipient[PR_DISPLAY_NAME] = $messageprops[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...
The constant PR_DISPLAY_NAME was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
492
			$recipient[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...
The constant PR_SENT_REPRESENTING_ADDRTYPE was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
493
			$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...
494
			$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...
495
			$recipient[PR_RECIPIENT_TRACKSTATUS] = $this->getTrackStatus($messageclass);
496
			$recipient[PR_RECIPIENT_TRACKSTATUS_TIME] = $deliverytime;
497
498
			// If this is a counter proposal, set the proposal properties in the recipient row
499
			if (isset($messageprops[$this->proptags['counter_proposal']])) {
500
				$recipient[PR_RECIPIENT_PROPOSEDSTARTTIME] = $messageprops[$this->proptags['proposed_start_whole']];
501
				$recipient[PR_RECIPIENT_PROPOSEDENDTIME] = $messageprops[$this->proptags['proposed_end_whole']];
502
				$recipient[PR_RECIPIENT_PROPOSED] = $messageprops[$this->proptags['counter_proposal']];
503
			}
504
505
			mapi_message_modifyrecipients($calendarItem, MODRECIP_ADD, [$recipient]);
506
			++$totalrecips;
507
			if ($recipient[PR_RECIPIENT_TRACKSTATUS] == olRecipientTrackStatusAccepted) {
508
				++$acceptedrecips;
509
			}
510
		}
511
512
		// TODO: Update counter proposal number property on message
513
		/*
514
		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.
515
		*/
516
		// If this is a counter proposal, set the counter proposal indicator boolean
517
		if (isset($messageprops[$this->proptags['counter_proposal']])) {
518
			$props = [];
519
			if ($messageprops[$this->proptags['counter_proposal']]) {
520
				$props[$this->proptags['counter_proposal']] = true;
521
			}
522
			else {
523
				$props[$this->proptags['counter_proposal']] = false;
524
			}
525
526
			mapi_setprops($calendarItem, $props);
527
		}
528
529
		mapi_savechanges($calendarItem);
530
		if (isset($attach)) {
531
			mapi_savechanges($attach);
532
			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...
533
		}
534
	}
535
536
	/**
537
	 * Process an incoming meeting request cancellation. This updates the
538
	 * appointment in your calendar to show that the meeting has been cancelled.
539
	 */
540
	public function processMeetingCancellation() {
541
		if (!$this->isMeetingCancellation()) {
542
			return;
543
		}
544
545
		if ($this->isLocalOrganiser()) {
546
			return;
547
		}
548
549
		if (!$this->isInCalendar()) {
550
			return;
551
		}
552
553
		$listProperties = $this->proptags;
554
		$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...
555
		$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...
556
		$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...
557
		$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...
558
		$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...
559
		$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...
560
		$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...
561
		$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...
562
		$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...
563
		$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...
564
		$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...
565
		$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

565
		$messageProps = /** @scrutinizer ignore-call */ mapi_getprops($this->message, $listProperties);
Loading history...
566
567
		$goid = $messageProps[$this->proptags['goid']];	// GlobalID (0x3)
568
		if (!isset($goid)) {
569
			return;
570
		}
571
572
		// get delegator store, if delegate is processing this cancellation
573
		if (isset($messageProps[PR_RCVD_REPRESENTING_ENTRYID])) {
574
			$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...
575
576
			$store = $delegatorStore['store'];
577
		}
578
		else {
579
			$store = $this->store;
580
		}
581
582
		// check for calendar access
583
		if ($this->checkCalendarWriteAccess($store) !== true) {
584
			// Throw an exception that we don't have write permissions on calendar folder,
585
			// allow caller to fill the error message
586
			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...
587
		}
588
589
		$calendarItem = $this->getCorrespondentCalendarItem(true);
590
		$basedate = $this->getBasedateFromGlobalID($goid);
591
592
		if ($calendarItem !== false) {
593
			// if basedate is provided and we could not find the item then it could be that we are processing
594
			// an exception so get the exception and process it
595
			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...
596
				$calendarItemProps = mapi_getprops($calendarItem, [$this->proptags['recurring']]);
597
				if ($calendarItemProps[$this->proptags['recurring']] === true) {
598
					$recurr = new Recurrence($store, $calendarItem);
599
600
					// Set message class
601
					$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...
602
603
					if ($recurr->isException($basedate)) {
604
						$recurr->modifyException($messageProps, $basedate);
605
					}
606
					else {
607
						$recurr->createException($messageProps, $basedate);
608
					}
609
				}
610
			}
611
			else {
612
				// set the properties of the cancellation object
613
				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

613
				/** @scrutinizer ignore-call */ 
614
    mapi_setprops($calendarItem, $messageProps);
Loading history...
614
			}
615
616
			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

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

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

702
					/** @scrutinizer ignore-call */ 
703
     mapi_setprops($this->message, [PR_PROCESSED => true]);
Loading history...
703
					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

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

756
		$messageprops = /** @scrutinizer ignore-call */ mapi_getprops($this->message);
Loading history...
757
		$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...
758
759
		if ($sendresponse) {
760
			$this->createResponse($tentative ? olResponseTentative : olResponseAccepted, $proposeNewTimeProps, $body, $store, $basedate, $calFolder);
761
		}
762
763
		/*
764
		 * Further processing depends on what user is receiving. User can receive recurring item, a single occurrence or a normal meeting.
765
		 * 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.
766
		 * 2) If single occurrence then find occurrence itself using globalID and if item is not found then use cleanGlobalID to find main recurring item
767
		 * 3) Normal meeting req are handled normally as they were handled previously.
768
		 *
769
		 * 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
770
		 * 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.
771
		 * If user is responding from calendar then item is opened and properties are set such as meetingstatus, responsestatus, busystatus etc.
772
		 */
773
		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...
774
			// This meeting request item is recurring, so find all occurrences and saves them all as exceptions to this meeting request item.
775
			if (isset($messageprops[$this->proptags['recurring']]) && $messageprops[$this->proptags['recurring']] == true) {
776
				$calendarItem = false;
777
778
				// Find main recurring item based on GlobalID (0x3)
779
				$items = $this->findCalendarItems($messageprops[$this->proptags['goid2']], $calFolder);
780
				if (is_array($items)) {
781
					foreach ($items as $key => $entryid) {
782
						$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

782
						$calendarItem = /** @scrutinizer ignore-call */ mapi_msgstore_openentry($store, $entryid);
Loading history...
783
					}
784
				}
785
786
				$processed = false;
787
				if (!$calendarItem) {
788
					// Recurring item not found, so create new meeting in Calendar
789
					$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

789
					$calendarItem = /** @scrutinizer ignore-call */ mapi_folder_createmessage($calFolder);
Loading history...
790
				}
791
				else {
792
					// we have found the main recurring item, check if this meeting request is already processed
793
					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...
794
						// only set required properties, other properties are already copied when processing this meeting request
795
						// for the first time
796
						$processed = true;
797
					}
798
					// While we applying updates of MR then all local categories will be removed,
799
					// So get the local categories of all occurrence before applying update from organiser.
800
					$localCategories = $this->getLocalCategories($calendarItem, $store, $calFolder);
801
				}
802
803
				if (!$processed) {
804
					// get all the properties and copy that to calendar item
805
					$props = mapi_getprops($this->message);
806
					// reset the PidLidMeetingType to Unspecified for outlook display the item
807
					$props[$this->proptags['meetingtype']] = mtgEmpty;
808
					/*
809
					 * the client which has sent this meeting request can generate wrong flagdueby
810
					 * time (mainly OL), so regenerate that property so we will always show reminder
811
					 * on right time
812
					 */
813
					if (isset($props[$this->proptags['reminderminutes']])) {
814
						$props[$this->proptags['flagdueby']] = $props[$this->proptags['startdate']] - ($props[$this->proptags['reminderminutes']] * 60);
815
					}
816
				}
817
				else {
818
					// only get required properties so we will not overwrite existing updated properties from calendar
819
					$props = mapi_getprops($this->message, [PR_ENTRYID]);
820
				}
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
				if(!isset($props[$this->proptags["recurring_pattern"]])) {
888
					$recurr = new Recurrence($store, $calendarItem);
889
					$recurr->saveRecurrencePattern();
890
				}
891
892
				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

892
				/** @scrutinizer ignore-call */ 
893
    mapi_savechanges($calendarItem);
Loading history...
893
894
				// After applying update of organiser all local categories of occurrence was removed,
895
				// So if local categories exist then apply it on respective occurrence.
896
				if (!empty($localCategories)) {
897
					$this->applyLocalCategories($calendarItem, $store, $localCategories);
898
				}
899
900
				if ($move) {
901
					// open wastebasket of currently logged in user and move the meeting request to it
902
					// for delegates this will be delegate's wastebasket folder
903
					$wastebasket = $this->openDefaultWastebasket($this->openDefaultStore());
904
					$sourcefolder = $this->openParentFolder();
905
					mapi_folder_copymessages($sourcefolder, [$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

905
					/** @scrutinizer ignore-call */ 
906
     mapi_folder_copymessages($sourcefolder, [$props[PR_ENTRYID]], $wastebasket, MESSAGE_MOVE);
Loading history...
906
				}
907
908
				$entryid = $props[PR_ENTRYID];
909
			}
910
			else {
911
				/**
912
				 * This meeting request is not recurring, so can be an exception or normal meeting.
913
				 * If exception then find main recurring item and update exception
914
				 * If main recurring item is not found then put exception into Calendar as normal meeting.
915
				 */
916
				$calendarItem = false;
917
918
				// We found basedate in GlobalID of this meeting request, so this meeting request if for an occurrence.
919
				if ($basedate) {
920
					// Find main recurring item from CleanGlobalID of this meeting request
921
					$items = $this->findCalendarItems($messageprops[$this->proptags['goid2']], $calFolder);
922
					if (is_array($items)) {
923
						foreach ($items as $key => $entryid) {
924
							$calendarItem = mapi_msgstore_openentry($store, $entryid);
925
						}
926
					}
927
928
					// Main recurring item is found, so now update exception
929
					if ($calendarItem) {
930
						$this->acceptException($calendarItem, $this->message, $basedate, $move, $tentative, $userAction, $store, $isDelegate);
931
						$calendarItemProps = mapi_getprops($calendarItem, [PR_ENTRYID]);
932
						$entryid = $calendarItemProps[PR_ENTRYID];
933
					}
934
				}
935
936
				if (!$calendarItem) {
937
					$items = $this->findCalendarItems($messageprops[$this->proptags['goid']], $calFolder);
938
					if (is_array($items)) {
939
						// Get local categories before deleting MR.
940
						$message = mapi_msgstore_openentry($store, $items[0]);
941
						$localCategories = mapi_getprops($message, [$this->proptags['categories']]);
942
						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

942
						/** @scrutinizer ignore-call */ 
943
      mapi_folder_deletemessages($calFolder, $items);
Loading history...
943
					}
944
945
					if ($move) {
946
						// All we have to do is open the default calendar,
947
						// set the message class correctly to be an appointment item
948
						// and move it to the calendar folder
949
						$sourcefolder = $this->openParentFolder();
950
951
						// create a new calendar message, and copy the message to there,
952
						// since we want to delete (move to wastebasket) the original message
953
						$old_entryid = mapi_getprops($this->message, [PR_ENTRYID]);
954
						$calmsg = mapi_folder_createmessage($calFolder);
955
						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

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

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

1109
						$reciptable = /** @scrutinizer ignore-call */ mapi_message_getrecipienttable($this->message);
Loading history...
1110
1111
						$recips = [];
1112
						// If delegate, then do not add the delegate in recipients
1113
						if ($isDelegate) {
1114
							$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...
1115
							$res = [
1116
								RES_PROPERTY,
1117
								[
1118
									RELOP => RELOP_NE,
1119
									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...
1120
									VALUE => [PR_EMAIL_ADDRESS => $delegate[PR_RECEIVED_BY_EMAIL_ADDRESS]],
1121
								],
1122
							];
1123
							$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

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

1223
		$messageprops = /** @scrutinizer ignore-call */ mapi_getprops($this->message, [$this->proptags['goid'], $this->proptags['goid2'], PR_RCVD_REPRESENTING_ENTRYID]);
Loading history...
1224
1225
		// If this meeting request is received by a delegate then open delegator's store.
1226
		if (isset($messageprops[PR_RCVD_REPRESENTING_ENTRYID])) {
1227
			$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...
1228
1229
			$store = $delegatorStore['store'];
1230
			$calFolder = $delegatorStore[PR_IPM_APPOINTMENT_ENTRYID];
1231
		}
1232
		else {
1233
			$calFolder = $this->openDefaultCalendar();
1234
			$store = $this->store;
1235
		}
1236
1237
		// check for calendar access before deleting the calendar item
1238
		if ($this->checkCalendarWriteAccess($store) !== true) {
1239
			// Throw an exception that we don't have write permissions on calendar folder,
1240
			// allow caller to fill the error message
1241
			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...
1242
		}
1243
1244
		$goid = $messageprops[$this->proptags['goid']];
1245
1246
		// First, find the items in the calendar by GlobalObjid (0x3)
1247
		$entryids = $this->findCalendarItems($goid, $calFolder);
1248
1249
		if (!$basedate) {
1250
			$basedate = $this->getBasedateFromGlobalID($goid);
1251
		}
1252
1253
		if ($sendresponse) {
1254
			$this->createResponse(olResponseDeclined, [], $body, $store, $basedate, $calFolder);
1255
		}
1256
1257
		if ($basedate) {
1258
			// use CleanGlobalObjid (0x23)
1259
			$calendaritems = $this->findCalendarItems($messageprops[$this->proptags['goid2']], $calFolder);
1260
1261
			if (is_array($calendaritems)) {
1262
				foreach ($calendaritems as $entryid) {
1263
					// Open each calendar item and set the properties of the cancellation object
1264
					$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

1264
					$calendaritem = /** @scrutinizer ignore-call */ mapi_msgstore_openentry($store, $entryid);
Loading history...
1265
1266
					// Recurring item is found, now delete exception
1267
					if ($calendaritem) {
1268
						$this->doRemoveExceptionFromCalendar($basedate, $calendaritem, $store);
1269
						$result = true;
1270
					}
1271
				}
1272
			}
1273
1274
			if ($this->isMeetingRequest()) {
1275
				$calendaritem = false;
1276
			}
1277
		}
1278
1279
		if (!$calendaritem) {
1280
			$calendar = $this->openDefaultCalendar($store);
1281
1282
			if (!empty($entryids)) {
1283
				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

1283
				/** @scrutinizer ignore-call */ 
1284
    mapi_folder_deletemessages($calendar, $entryids);
Loading history...
1284
			}
1285
1286
			// All we have to do to decline, is to move the item to the waste basket
1287
			$wastebasket = $this->openDefaultWastebasket($this->openDefaultStore());
1288
			$sourcefolder = $this->openParentFolder();
1289
1290
			$messageprops = mapi_getprops($this->message, [PR_ENTRYID]);
1291
1292
			// Release the message
1293
			$this->message = null;
1294
1295
			// Move the message to the waste basket
1296
			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

1296
			/** @scrutinizer ignore-call */ 
1297
   mapi_folder_copymessages($sourcefolder, [$messageprops[PR_ENTRYID]], $wastebasket, MESSAGE_MOVE);
Loading history...
1297
1298
			$result = true;
1299
		}
1300
1301
		return $result;
1302
	}
1303
1304
	/**
1305
	 * Removes a meeting request from the calendar when the user presses the
1306
	 * 'remove from calendar' button in response to a meeting cancellation.
1307
	 *
1308
	 * @param mixed $basedate if specified contains starttime of day of an occurrence
1309
	 *
1310
	 * @return null|false
1311
	 */
1312
	public function doRemoveFromCalendar($basedate) {
1313
		if ($this->isLocalOrganiser()) {
1314
			return false;
1315
		}
1316
1317
		$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 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

1317
		$messageprops = /** @scrutinizer ignore-call */ mapi_getprops($this->message, [PR_ENTRYID, $this->proptags['goid'], PR_RCVD_REPRESENTING_ENTRYID, PR_MESSAGE_CLASS]);
Loading history...
1318
1319
		$goid = $messageprops[$this->proptags['goid']];
1320
1321
		if (isset($messageprops[PR_RCVD_REPRESENTING_ENTRYID])) {
1322
			$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...
1323
1324
			$store = $delegatorStore['store'];
1325
			$calFolder = $delegatorStore[PR_IPM_APPOINTMENT_ENTRYID];
1326
		}
1327
		else {
1328
			$store = $this->store;
1329
			$calFolder = $this->openDefaultCalendar();
1330
		}
1331
1332
		// check for calendar access before deleting the calendar item
1333
		if ($this->checkCalendarWriteAccess($store) !== true) {
1334
			// Throw an exception that we don't have write permissions on calendar folder,
1335
			// allow caller to fill the error message
1336
			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...
1337
		}
1338
1339
		$wastebasket = $this->openDefaultWastebasket($this->openDefaultStore());
1340
		// get the source folder of the meeting message
1341
		$sourcefolder = $this->openParentFolder();
1342
1343
		// Check if the message is a meeting request in the inbox or a calendaritem by checking the message class
1344
		if ($this->isMeetingCancellation($messageprops[PR_MESSAGE_CLASS])) {
1345
			// get the basedate to check for exception
1346
			$basedate = $this->getBasedateFromGlobalID($goid);
1347
1348
			$calendarItem = $this->getCorrespondentCalendarItem(true);
1349
1350
			if ($calendarItem !== false) {
1351
				// basedate is provided so open exception
1352
				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...
1353
					$exception = $this->getExceptionItem($calendarItem, $basedate);
1354
1355
					if ($exception !== false) {
0 ignored issues
show
The condition $exception !== false is always true.
Loading history...
1356
						// exception found, remove it from calendar
1357
						$this->doRemoveExceptionFromCalendar($basedate, $calendarItem, $store);
1358
					}
1359
				}
1360
				else {
1361
					// remove normal / recurring series from calendar
1362
					$entryids = mapi_getprops($calendarItem, [PR_ENTRYID]);
1363
1364
					$entryids = [$entryids[PR_ENTRYID]];
1365
1366
					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

1366
					/** @scrutinizer ignore-call */ 
1367
     mapi_folder_copymessages($calFolder, $entryids, $wastebasket, MESSAGE_MOVE);
Loading history...
1367
				}
1368
			}
1369
1370
			// Release the message, because we are going to move it to wastebasket
1371
			$this->message = null;
1372
1373
			// Move the cancellation mail to wastebasket
1374
			mapi_folder_copymessages($sourcefolder, [$messageprops[PR_ENTRYID]], $wastebasket, MESSAGE_MOVE);
1375
		}
1376
		else {
1377
			// Here only properties are set on calendaritem, because user is responding from calendar.
1378
			if ($basedate) {
1379
				// remove the occurrence
1380
				$this->doRemoveExceptionFromCalendar($basedate, $this->message, $store);
1381
			}
1382
			else {
1383
				// remove normal/recurring meeting item.
1384
				// Move the message to the waste basket
1385
				mapi_folder_copymessages($sourcefolder, [$messageprops[PR_ENTRYID]], $wastebasket, MESSAGE_MOVE);
1386
			}
1387
		}
1388
	}
1389
1390
	/**
1391
	 * Function can be used to cancel any existing meeting and send cancellation mails to attendees.
1392
	 * Should only be called from meeting object from calendar.
1393
	 *
1394
	 * @param mixed $basedate (optional) basedate of occurrence which should be cancelled
1395
	 *
1396
	 * @FIXME cancellation mail is also sent to attendee which has declined the meeting
1397
	 * @FIXME don't send canellation mail when cancelling meeting from past
1398
	 */
1399
	public function doCancelInvitation($basedate = false) {
1400
		if (!$this->isLocalOrganiser()) {
1401
			return;
1402
		}
1403
1404
		// check write access for delegate
1405
		if ($this->checkCalendarWriteAccess($this->store) !== true) {
1406
			// Throw an exception that we don't have write permissions on calendar folder,
1407
			// error message will be filled by module
1408
			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...
1409
		}
1410
1411
		$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

1411
		$messageProps = /** @scrutinizer ignore-call */ mapi_getprops($this->message, [PR_ENTRYID, $this->proptags['recurring']]);
Loading history...
1412
1413
		if (isset($messageProps[$this->proptags['recurring']]) && $messageProps[$this->proptags['recurring']] === true) {
1414
			// cancellation of recurring series or one occurrence
1415
			$recurrence = new Recurrence($this->store, $this->message);
1416
1417
			// if basedate is specified then we are cancelling only one occurrence, so create exception for that occurrence
1418
			if ($basedate) {
1419
				$recurrence->createException([], $basedate, true);
1420
			}
1421
1422
			// update the meeting request
1423
			$this->updateMeetingRequest();
1424
1425
			// send cancellation mails
1426
			$this->sendMeetingRequest(true, dgettext('zarafa', 'Canceled') . ': ', $basedate);
1427
1428
			// save changes in the message
1429
			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

1429
			/** @scrutinizer ignore-call */ 
1430
   mapi_savechanges($this->message);
Loading history...
1430
		}
1431
		else {
1432
			// cancellation of normal meeting request
1433
			// Send the cancellation
1434
			$this->updateMeetingRequest();
1435
			$this->sendMeetingRequest(true, dgettext('zarafa', 'Canceled') . ': ');
1436
1437
			// save changes in the message
1438
			mapi_savechanges($this->message);
1439
		}
1440
1441
		// if basedate is specified then we have already created exception of it so nothing should be done now
1442
		// but when cancelling normal / recurring meeting request we need to remove meeting from calendar
1443
		if ($basedate === false) {
1444
			// get the wastebasket folder, for delegate this will give wastebasket of delegate
1445
			$wastebasket = $this->openDefaultWastebasket($this->openDefaultStore());
1446
1447
			// get the source folder of the meeting message
1448
			$sourcefolder = $this->openParentFolder();
1449
1450
			// Move the message to the deleted items
1451
			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

1451
			/** @scrutinizer ignore-call */ 
1452
   mapi_folder_copymessages($sourcefolder, [$messageProps[PR_ENTRYID]], $wastebasket, MESSAGE_MOVE);
Loading history...
1452
		}
1453
	}
1454
1455
	/**
1456
	 * Convert epoch to MAPI FileTime, number of 100-nanosecond units since
1457
	 * the start of January 1, 1601.
1458
	 * https://msdn.microsoft.com/en-us/library/office/cc765906.aspx.
1459
	 *
1460
	 * @param int $epoch the current epoch
1461
	 *
1462
	 * @return int the MAPI FileTime equalevent to the given epoch time
1463
	 */
1464
	public function epochToMapiFileTime($epoch) {
1465
		$nanoseconds_between_epoch = 116444736000000000;
1466
1467
		return ($epoch * 10000000) + $nanoseconds_between_epoch;
1468
	}
1469
1470
	/**
1471
	 * Sets the properties in the message so that is can be sent
1472
	 * as a meeting request. The caller has to submit the message. This
1473
	 * is only used for new MeetingRequests. Pass the appointment item as $message
1474
	 * in the constructor to do this.
1475
	 *
1476
	 * @param mixed $basedate
1477
	 */
1478
	public function setMeetingRequest($basedate = false): void {
1479
		$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

1479
		$props = /** @scrutinizer ignore-call */ mapi_getprops($this->message, [$this->proptags['updatecounter']]);
Loading history...
1480
1481
		// Create a new global id for this item
1482
		// https://msdn.microsoft.com/en-us/library/ee160198(v=exchg.80).aspx
1483
		$goid = pack('H*', '040000008200E00074C5B7101A82E00800000000');
1484
		/*
1485
		$year = gmdate('Y');
1486
		$month = gmdate('n');
1487
		$day = gmdate('j');
1488
		$goid .= pack('n', $year);
1489
		$goid .= pack('C', $month);
1490
		$goid .= pack('C', $day);
1491
		*/
1492
		// Creation Time
1493
		$time = $this->epochToMapiFileTime(time());
1494
		$goid .= pack('V', $time & 0xFFFFFFFF);
1495
		$goid .= pack('V', $time >> 32);
1496
		// 8 Zeros
1497
		$goid .= pack('H*', '0000000000000000');
1498
		// Length of the random data
1499
		$goid .= pack('V', 16);
1500
		// Random data.
1501
		for ($i = 0; $i < 16; ++$i) {
1502
			$goid .= chr(rand(0, 255));
1503
		}
1504
1505
		// Create a new appointment id for this item
1506
		$apptid = rand();
1507
1508
		$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...
1509
		$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...
1510
		$props[$this->proptags['goid']] = $goid;
1511
		$props[$this->proptags['goid2']] = $goid;
1512
1513
		if (!isset($props[$this->proptags['updatecounter']])) {
1514
			$props[$this->proptags['updatecounter']] = 0;			// OL also starts sequence no with zero.
1515
			$props[$this->proptags['last_updatecounter']] = 0;
1516
		}
1517
1518
		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

1518
		/** @scrutinizer ignore-call */ 
1519
  mapi_setprops($this->message, $props);
Loading history...
1519
	}
1520
1521
	/**
1522
	 * Sends a meeting request by copying it to the outbox, converting
1523
	 * the message class, adding some properties that are required only
1524
	 * for sending the message and submitting the message. Set cancel to
1525
	 * true if you wish to completely cancel the meeting request. You can
1526
	 * specify an optional 'prefix' to prefix the sent message, which is normally
1527
	 * 'Canceled: '.
1528
	 *
1529
	 * @param mixed $cancel
1530
	 * @param mixed $prefix
1531
	 * @param mixed $basedate
1532
	 * @param mixed $modifiedRecips
1533
	 * @param mixed $deletedRecips
1534
	 *
1535
	 * @return (int|mixed)[]|true
1536
	 *
1537
	 * @psalm-return array{error: 1|3|4, displayname: mixed}|true
1538
	 */
1539
	public function sendMeetingRequest($cancel, $prefix = false, $basedate = false, $modifiedRecips = false, $deletedRecips = false) {
1540
		$this->includesResources = false;
1541
		$this->nonAcceptingResources = [];
1542
1543
		// Get the properties of the message
1544
		$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

1544
		$messageprops = /** @scrutinizer ignore-call */ mapi_getprops($this->message, [$this->proptags['recurring']]);
Loading history...
1545
1546
		/*
1547
		 * Submit message to non-resource recipients
1548
		 */
1549
		// Set BusyStatus to olTentative (1)
1550
		// Set MeetingStatus to olMeetingReceived
1551
		// Set ResponseStatus to olResponseNotResponded
1552
1553
		/*
1554
		 * While sending recurrence meeting exceptions are not sent as attachments
1555
		 * because first all exceptions are sent and then recurrence meeting is sent.
1556
		 */
1557
		if (isset($messageprops[$this->proptags['recurring']]) && $messageprops[$this->proptags['recurring']] && !$basedate) {
1558
			// Book resource
1559
			$this->bookResources($this->message, $cancel, $prefix);
1560
1561
			if (!$this->errorSetResource) {
1562
				$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

1562
				$recurr = new Recurrence(/** @scrutinizer ignore-type */ $this->openDefaultStore(), $this->message);
Loading history...
1563
1564
				// First send meetingrequest for recurring item
1565
				$this->submitMeetingRequest($this->message, $cancel, $prefix, false, $recurr, false, $modifiedRecips, $deletedRecips);
1566
1567
				// Then send all meeting request for all exceptions
1568
				$exceptions = $recurr->getAllExceptions();
1569
				if ($exceptions) {
1570
					foreach ($exceptions as $exceptionBasedate) {
1571
						$attach = $recurr->getExceptionAttachment($exceptionBasedate);
1572
1573
						if ($attach) {
1574
							$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

1574
							$occurrenceItem = /** @scrutinizer ignore-call */ mapi_attach_openobj($attach, MAPI_MODIFY);
Loading history...
1575
							$this->submitMeetingRequest($occurrenceItem, $cancel, false, $exceptionBasedate, $recurr, false, $modifiedRecips, $deletedRecips);
1576
							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

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

1641
		$messageprops = /** @scrutinizer ignore-call */ mapi_getprops($this->message, [$this->proptags['last_updatecounter'], $this->proptags['goid']]);
Loading history...
1642
1643
		if (!isset($messageprops[$this->proptags['goid']])) {
1644
			$this->setMeetingRequest($basedate);
1645
		}
1646
		else {
1647
			$counter = (isset($messageprops[$this->proptags['last_updatecounter']]) ?? 0) + 1;
1648
1649
			// increment value of last_updatecounter, last_updatecounter will be common for recurring series
1650
			// so even if you sending an exception only you need to update the last_updatecounter in the recurring series message
1651
			// this way we can make sure that every time we will be using a uniwue number for every operation
1652
			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

1652
			/** @scrutinizer ignore-call */ 
1653
   mapi_setprops($this->message, [$this->proptags['last_updatecounter'] => $counter]);
Loading history...
1653
		}
1654
	}
1655
1656
	/**
1657
	 * Returns TRUE if we are the organiser of the meeting. Can be used with any type of meeting object.
1658
	 */
1659
	public function isLocalOrganiser(): bool {
1660
		$props = mapi_getprops($this->message, [$this->proptags['goid'], 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

1660
		$props = /** @scrutinizer ignore-call */ mapi_getprops($this->message, [$this->proptags['goid'], 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...
1661
1662
		if (!$this->isMeetingRequest($props[PR_MESSAGE_CLASS]) && !$this->isMeetingRequestResponse($props[PR_MESSAGE_CLASS]) && !$this->isMeetingCancellation($props[PR_MESSAGE_CLASS])) {
1663
			// we are checking with calendar item
1664
			$calendarItem = $this->message;
1665
		}
1666
		else {
1667
			// we are checking with meeting request / response / cancellation mail
1668
			// get calendar items
1669
			$calendarItem = $this->getCorrespondentCalendarItem(true);
1670
		}
1671
1672
		// even if we have received request/response for exception/occurrence then also
1673
		// we can check recurring series for organizer, no need to check with exception/occurrence
1674
1675
		if ($calendarItem !== false) {
1676
			$messageProps = mapi_getprops($calendarItem, [$this->proptags['responsestatus']]);
1677
1678
			if (isset($messageProps[$this->proptags['responsestatus']]) && $messageProps[$this->proptags['responsestatus']] === olResponseOrganized) {
1679
				return true;
1680
			}
1681
		}
1682
1683
		return false;
1684
	}
1685
1686
	/*
1687
	 * Support functions - INTERNAL ONLY
1688
	 ***************************************************************************************************
1689
	 */
1690
1691
	/**
1692
	 * Return the tracking status of a recipient based on the IPM class (passed).
1693
	 *
1694
	 * @param mixed $class
1695
	 */
1696
	public function getTrackStatus($class) {
1697
		$status = olRecipientTrackStatusNone;
1698
1699
		switch ($class) {
1700
			case 'IPM.Schedule.Meeting.Resp.Pos':
1701
				$status = olRecipientTrackStatusAccepted;
1702
				break;
1703
1704
			case 'IPM.Schedule.Meeting.Resp.Tent':
1705
				$status = olRecipientTrackStatusTentative;
1706
				break;
1707
1708
			case 'IPM.Schedule.Meeting.Resp.Neg':
1709
				$status = olRecipientTrackStatusDeclined;
1710
				break;
1711
		}
1712
1713
		return $status;
1714
	}
1715
1716
	/**
1717
	 * Function returns MAPIFolder resource of the folder that currently holds this meeting/meeting request
1718
	 * object.
1719
	 */
1720
	public function openParentFolder() {
1721
		$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

1721
		$messageprops = /** @scrutinizer ignore-call */ mapi_getprops($this->message, [PR_PARENT_ENTRYID]);
Loading history...
1722
1723
		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

1723
		return /** @scrutinizer ignore-call */ mapi_msgstore_openentry($this->store, $messageprops[PR_PARENT_ENTRYID]);
Loading history...
1724
	}
1725
1726
	/**
1727
	 * Function will return resource of the default calendar folder of store.
1728
	 *
1729
	 * @param mixed $store {optional} user store whose default calendar should be opened
1730
	 *
1731
	 * @return resource default calendar folder of store
1732
	 */
1733
	public function openDefaultCalendar($store = false) {
1734
		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...
1735
	}
1736
1737
	/**
1738
	 * Function will return resource of the default outbox folder of store.
1739
	 *
1740
	 * @param mixed $store {optional} user store whose default outbox should be opened
1741
	 *
1742
	 * @return resource default outbox folder of store
1743
	 */
1744
	public function openDefaultOutbox($store = false) {
1745
		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...
1746
	}
1747
1748
	/**
1749
	 * Function will return resource of the default wastebasket folder of store.
1750
	 *
1751
	 * @param mixed $store {optional} user store whose default wastebasket should be opened
1752
	 *
1753
	 * @return resource default wastebasket folder of store
1754
	 */
1755
	public function openDefaultWastebasket($store = false) {
1756
		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...
1757
	}
1758
1759
	/**
1760
	 * Function will return resource of the default calendar folder of store.
1761
	 *
1762
	 * @param mixed $store {optional} user store whose default calendar should be opened
1763
	 *
1764
	 * @return bool|string default calendar folder of store
1765
	 */
1766
	public function getDefaultWastebasketEntryID($store = false) {
1767
		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...
1768
	}
1769
1770
	/**
1771
	 * Function will return resource of the default sent mail folder of store.
1772
	 *
1773
	 * @param mixed $store {optional} user store whose default sent mail should be opened
1774
	 *
1775
	 * @return bool|string default sent mail folder of store
1776
	 */
1777
	public function getDefaultSentmailEntryID($store = false) {
1778
		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...
1779
	}
1780
1781
	/**
1782
	 * Function will return entryid of any default folder of store. This method is useful when you want
1783
	 * to get entryid of folder which is stored as properties of inbox folder
1784
	 * (PR_IPM_APPOINTMENT_ENTRYID, PR_IPM_CONTACT_ENTRYID, PR_IPM_DRAFTS_ENTRYID, PR_IPM_JOURNAL_ENTRYID, PR_IPM_NOTE_ENTRYID, PR_IPM_TASK_ENTRYID).
1785
	 *
1786
	 * @param int   $prop  proptag of the folder for which we want to get entryid
1787
	 * @param mixed $store {optional} user store from which we need to get entryid of default folder
1788
	 *
1789
	 * @return bool|string entryid of folder pointed by $prop
1790
	 */
1791
	public function getDefaultFolderEntryID($prop, $store = false) {
1792
		try {
1793
			$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

1793
			$inbox = /** @scrutinizer ignore-call */ mapi_msgstore_getreceivefolder($store ? $store : $this->store);
Loading history...
1794
			$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

1794
			$inboxprops = /** @scrutinizer ignore-call */ mapi_getprops($inbox, [$prop]);
Loading history...
1795
			if (isset($inboxprops[$prop])) {
1796
				return $inboxprops[$prop];
1797
			}
1798
		}
1799
		catch (MAPIException $e) {
1800
			// public store doesn't support this method
1801
			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...
1802
				// don't propagate this error to parent handlers, if store doesn't support it
1803
				$e->setHandled();
1804
			}
1805
		}
1806
1807
		return false;
1808
	}
1809
1810
	/**
1811
	 * Function will return resource of any default folder of store.
1812
	 *
1813
	 * @param int   $prop  proptag of the folder that we want to open
1814
	 * @param mixed $store {optional} user store from which we need to open default folder
1815
	 *
1816
	 * @return resource default folder of store
1817
	 */
1818
	public function openDefaultFolder($prop, $store = false) {
1819
		$folder = false;
1820
		$entryid = $this->getDefaultFolderEntryID($prop, $store);
1821
1822
		if ($entryid !== false) {
1823
			$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

1823
			$folder = /** @scrutinizer ignore-call */ mapi_msgstore_openentry($store ? $store : $this->store, $entryid);
Loading history...
1824
		}
1825
1826
		return $folder;
1827
	}
1828
1829
	/**
1830
	 * Function will return entryid of default folder from store. This method is useful when you want
1831
	 * to get entryid of folder which is stored as store properties
1832
	 * (PR_IPM_FAVORITES_ENTRYID, PR_IPM_OUTBOX_ENTRYID, PR_IPM_SENTMAIL_ENTRYID, PR_IPM_WASTEBASKET_ENTRYID).
1833
	 *
1834
	 * @param int   $prop  proptag of the folder whose entryid we want to get
1835
	 * @param mixed $store {optional} user store from which we need to get entryid of default folder
1836
	 *
1837
	 * @return bool|string entryid of default folder from store
1838
	 */
1839
	public function getBaseEntryID($prop, $store = false) {
1840
		$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

1840
		$storeprops = /** @scrutinizer ignore-call */ mapi_getprops($store ? $store : $this->store, [$prop]);
Loading history...
1841
		if (!isset($storeprops[$prop])) {
1842
			return false;
1843
		}
1844
1845
		return $storeprops[$prop];
1846
	}
1847
1848
	/**
1849
	 * Function will return resource of any default folder of store.
1850
	 *
1851
	 * @param int   $prop  proptag of the folder that we want to open
1852
	 * @param mixed $store {optional} user store from which we need to open default folder
1853
	 *
1854
	 * @return resource default folder of store
1855
	 */
1856
	public function openBaseFolder($prop, $store = false) {
1857
		$folder = false;
1858
		$entryid = $this->getBaseEntryID($prop, $store);
1859
1860
		if ($entryid !== false) {
1861
			$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

1861
			$folder = /** @scrutinizer ignore-call */ mapi_msgstore_openentry($store ? $store : $this->store, $entryid);
Loading history...
1862
		}
1863
1864
		return $folder;
1865
	}
1866
1867
	/**
1868
	 * Function checks whether user has access over the specified folder or not.
1869
	 *
1870
	 * @param string $entryid entryid The entryid of the folder to check
1871
	 * @param mixed  $store   (optional) store from which folder should be opened
1872
	 *
1873
	 * @return bool true if user has an access over the folder, false if not
1874
	 */
1875
	public function checkFolderWriteAccess($entryid, $store = false) {
1876
		$accessToFolder = false;
1877
1878
		if (!empty($entryid)) {
1879
			if ($store === false) {
1880
				$store = $this->store;
1881
			}
1882
1883
			try {
1884
				$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

1884
				$folder = /** @scrutinizer ignore-call */ mapi_msgstore_openentry($store, $entryid);
Loading history...
1885
				$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

1885
				$folderProps = /** @scrutinizer ignore-call */ mapi_getprops($folder, [PR_ACCESS]);
Loading history...
1886
				if (($folderProps[PR_ACCESS] & MAPI_ACCESS_CREATE_CONTENTS) === MAPI_ACCESS_CREATE_CONTENTS) {
1887
					$accessToFolder = true;
1888
				}
1889
			}
1890
			catch (MAPIException $e) {
1891
				// we don't have rights to open folder, so return false
1892
				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...
1893
					return $accessToFolder;
1894
				}
1895
1896
				// rethrow other errors
1897
				throw $e;
1898
			}
1899
		}
1900
1901
		return $accessToFolder;
1902
	}
1903
1904
	/**
1905
	 * Function checks whether user has access over the specified folder or not.
1906
	 *
1907
	 * @param mixed $store
1908
	 *
1909
	 * @return bool true if user has an access over the folder, false if not
1910
	 */
1911
	public function checkCalendarWriteAccess($store = false) {
1912
		if ($store === false) {
1913
			// If this meeting request is received by a delegate then open delegator's store.
1914
			$messageProps = mapi_getprops($this->message, [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

1914
			$messageProps = /** @scrutinizer ignore-call */ mapi_getprops($this->message, [PR_RCVD_REPRESENTING_ENTRYID]);
Loading history...
1915
			if (isset($messageProps[PR_RCVD_REPRESENTING_ENTRYID])) {
1916
				$delegatorStore = $this->getDelegatorStore($messageProps[PR_RCVD_REPRESENTING_ENTRYID]);
1917
1918
				$store = $delegatorStore['store'];
1919
			}
1920
			else {
1921
				$store = $this->store;
1922
			}
1923
		}
1924
1925
		// If the store is a public folder, the calendar folder is the PARENT_ENTRYID of the calendar item
1926
		$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...
1927
		if (isset($provider[PR_MDB_PROVIDER]) && $provider[PR_MDB_PROVIDER] === ZARAFA_STORE_PUBLIC_GUID) {
1928
			$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...
1929
			$entryid = $entryid[PR_PARENT_ENTRYID];
1930
		}
1931
		else {
1932
			$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...
1933
			if ($entryid === false) {
1934
				$entryid = $this->getBaseEntryID(PR_IPM_APPOINTMENT_ENTRYID, $store);
1935
			}
1936
1937
			if ($entryid === false) {
1938
				return false;
1939
			}
1940
		}
1941
1942
		return $this->checkFolderWriteAccess($entryid, $store);
1943
	}
1944
1945
	/**
1946
	 * Function will resolve the user and open its store.
1947
	 *
1948
	 * @param string $ownerentryid the entryid of the user
1949
	 *
1950
	 * @return resource store of the user
1951
	 */
1952
	public function openCustomUserStore($ownerentryid) {
1953
		$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

1953
		$ab = /** @scrutinizer ignore-call */ mapi_openaddressbook($this->session);
Loading history...
1954
1955
		try {
1956
			$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

1956
			$mailuser = /** @scrutinizer ignore-call */ mapi_ab_openentry($ab, $ownerentryid);
Loading history...
1957
		}
1958
		catch (MAPIException $e) {
1959
			return;
1960
		}
1961
1962
		$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

1962
		$mailuserprops = /** @scrutinizer ignore-call */ mapi_getprops($mailuser, [PR_EMAIL_ADDRESS]);
Loading history...
1963
		$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

1963
		$storeid = /** @scrutinizer ignore-call */ mapi_msgstore_createentryid($this->store, $mailuserprops[PR_EMAIL_ADDRESS]);
Loading history...
1964
1965
		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

1965
		return /** @scrutinizer ignore-call */ mapi_openmsgstore($this->session, $storeid);
Loading history...
1966
	}
1967
1968
	/**
1969
	 * Function which sends response to organizer when attendee accepts, declines or proposes new time to a received meeting request.
1970
	 *
1971
	 * @param int   $status              response status of attendee
1972
	 * @param array $proposeNewTimeProps properties of attendee's proposal
1973
	 * @param mixed $body
1974
	 * @param mixed $store
1975
	 * @param mixed $basedate            date of occurrence which attendee has responded
1976
	 * @param mixed $calFolder
1977
	 */
1978
	public function createResponse($status, $proposeNewTimeProps, $body, $store, $basedate, $calFolder): void {
1979
		$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

1979
		$messageprops = /** @scrutinizer ignore-call */ mapi_getprops($this->message, [
Loading history...
1980
			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...
1981
			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...
1982
			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...
1983
			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...
1984
			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...
1985
			$this->proptags['goid'],
1986
			$this->proptags['goid2'],
1987
			$this->proptags['location'],
1988
			$this->proptags['startdate'],
1989
			$this->proptags['duedate'],
1990
			$this->proptags['recurring'],
1991
			$this->proptags['recurring_pattern'],
1992
			$this->proptags['recurrence_data'],
1993
			$this->proptags['timezone_data'],
1994
			$this->proptags['timezone'],
1995
			$this->proptags['updatecounter'],
1996
			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...
1997
			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...
1998
			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...
1999
			$this->proptags['is_exception'],
2000
		]);
2001
2002
		$props = [];
2003
2004
		if ($basedate !== false && !$this->isMeetingRequest($messageprops[PR_MESSAGE_CLASS])) {
2005
			// we are creating response from a recurring calendar item object
2006
			// We found basedate,so opened occurrence and get properties.
2007
			$recurr = new Recurrence($store, $this->message);
2008
			$exception = $recurr->getExceptionAttachment($basedate);
2009
2010
			if ($exception) {
2011
				// Exception found, Now retrieve properties
2012
				$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

2012
				$imessage = /** @scrutinizer ignore-call */ mapi_attach_openobj($exception, 0);
Loading history...
2013
				$imsgprops = mapi_getprops($imessage);
2014
2015
				// If location is provided, copy it to the response
2016
				if (isset($imsgprops[$this->proptags['location']])) {
2017
					$messageprops[$this->proptags['location']] = $imsgprops[$this->proptags['location']];
2018
				}
2019
2020
				// Update $messageprops with timings of occurrence
2021
				$messageprops[$this->proptags['startdate']] = $imsgprops[$this->proptags['startdate']];
2022
				$messageprops[$this->proptags['duedate']] = $imsgprops[$this->proptags['duedate']];
2023
2024
				// Meeting related properties
2025
				$props[$this->proptags['meetingstatus']] = $imsgprops[$this->proptags['meetingstatus']];
2026
				$props[$this->proptags['responsestatus']] = $imsgprops[$this->proptags['responsestatus']];
2027
				$props[PR_SUBJECT] = $imsgprops[PR_SUBJECT];
2028
			}
2029
			else {
2030
				// Exceptions is deleted.
2031
				// Update $messageprops with timings of occurrence
2032
				$messageprops[$this->proptags['startdate']] = $recurr->getOccurrenceStart($basedate);
2033
				$messageprops[$this->proptags['duedate']] = $recurr->getOccurrenceEnd($basedate);
2034
2035
				$props[$this->proptags['meetingstatus']] = olNonMeeting;
2036
				$props[$this->proptags['responsestatus']] = olResponseNone;
2037
			}
2038
2039
			$props[$this->proptags['recurring']] = false;
2040
			$props[$this->proptags['is_exception']] = true;
2041
		}
2042
		else {
2043
			// we are creating a response from meeting request mail (it could be recurring or non-recurring)
2044
			// Send all recurrence info in response, if this is a recurrence meeting.
2045
			$isRecurring = isset($messageprops[$this->proptags['recurring']]) && $messageprops[$this->proptags['recurring']];
2046
			$isException = isset($messageprops[$this->proptags['is_exception']]) && $messageprops[$this->proptags['is_exception']];
2047
			if ($isRecurring || $isException) {
2048
				if ($isRecurring) {
2049
					$props[$this->proptags['recurring']] = $messageprops[$this->proptags['recurring']];
2050
				}
2051
				if ($isException) {
2052
					$props[$this->proptags['is_exception']] = $messageprops[$this->proptags['is_exception']];
2053
				}
2054
				$calendaritems = $this->findCalendarItems($messageprops[$this->proptags['goid2']], $calFolder);
2055
2056
				$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

2056
				$calendaritem = /** @scrutinizer ignore-call */ mapi_msgstore_openentry($store, $calendaritems[0]);
Loading history...
2057
				$recurr = new Recurrence($store, $calendaritem);
2058
			}
2059
		}
2060
2061
		// we are sending a response for recurring meeting request (or exception), so set some required properties
2062
		if (isset($recurr) && $recurr) {
2063
			if (!empty($messageprops[$this->proptags['recurring_pattern']])) {
2064
				$props[$this->proptags['recurring_pattern']] = $messageprops[$this->proptags['recurring_pattern']];
2065
			}
2066
2067
			if (!empty($messageprops[$this->proptags['recurrence_data']])) {
2068
				$props[$this->proptags['recurrence_data']] = $messageprops[$this->proptags['recurrence_data']];
2069
			}
2070
2071
			$props[$this->proptags['timezone_data']] = $messageprops[$this->proptags['timezone_data']];
2072
			$props[$this->proptags['timezone']] = $messageprops[$this->proptags['timezone']];
2073
2074
			$this->generateRecurDates($recurr, $messageprops, $props);
2075
		}
2076
2077
		// Create a response message
2078
		$recip = [];
2079
		$recip[PR_ENTRYID] = $messageprops[PR_SENT_REPRESENTING_ENTRYID];
2080
		$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...
2081
		$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...
2082
		$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...
2083
		$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...
2084
		$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...
2085
2086
		$subjectprefix = '';
2087
2088
		switch ($status) {
2089
			case olResponseAccepted:
2090
				$classpostfix = 'Pos';
2091
				$subjectprefix = dgettext('zarafa', 'Accepted');
2092
				break;
2093
2094
			case olResponseDeclined:
2095
				$classpostfix = 'Neg';
2096
				$subjectprefix = dgettext('zarafa', 'Declined');
2097
				break;
2098
2099
			case olResponseTentative:
2100
				$classpostfix = 'Tent';
2101
				$subjectprefix = dgettext('zarafa', 'Tentatively accepted');
2102
				break;
2103
		}
2104
2105
		if (!empty($proposeNewTimeProps)) {
2106
			// if attendee has proposed new time then change subject prefix
2107
			$subjectprefix = dgettext('zarafa', 'New Time Proposed');
2108
		}
2109
2110
		$props[PR_SUBJECT] = $subjectprefix . ': ' . $messageprops[PR_SUBJECT];
2111
2112
		$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...
2113
		if (isset($messageprops[PR_OWNER_APPT_ID])) {
2114
			$props[PR_OWNER_APPT_ID] = $messageprops[PR_OWNER_APPT_ID];
2115
		}
2116
2117
		// Set GlobalId AND CleanGlobalId, if exception then also set basedate into GlobalId(0x3).
2118
		$props[$this->proptags['goid']] = $this->setBasedateInGlobalID($messageprops[$this->proptags['goid2']], $basedate);
2119
		$props[$this->proptags['goid2']] = $messageprops[$this->proptags['goid2']];
2120
		$props[$this->proptags['updatecounter']] = isset($messageprops[$this->proptags['updatecounter']]) ? $messageprops[$this->proptags['updatecounter']] : 0;
2121
2122
		if (!empty($proposeNewTimeProps)) {
2123
			// merge proposal properties to message properties which will be sent to organizer
2124
			$props = $proposeNewTimeProps + $props;
2125
		}
2126
2127
		// Set body message in Appointment
2128
		if (isset($body)) {
2129
			$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...
2130
		}
2131
2132
		// PR_START_DATE/PR_END_DATE is used in the UI in Outlook on the response message
2133
		$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...
2134
		$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...
2135
2136
		// Set startdate and duedate in response mail.
2137
		$props[$this->proptags['startdate']] = $messageprops[$this->proptags['startdate']];
2138
		$props[$this->proptags['duedate']] = $messageprops[$this->proptags['duedate']];
2139
2140
		// responselocation is used in the UI in Outlook on the response message
2141
		if (isset($messageprops[$this->proptags['location']])) {
2142
			$props[$this->proptags['responselocation']] = $messageprops[$this->proptags['location']];
2143
			$props[$this->proptags['location']] = $messageprops[$this->proptags['location']];
2144
		}
2145
2146
		$message = $this->createOutgoingMessage($store);
2147
2148
		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

2148
		/** @scrutinizer ignore-call */ 
2149
  mapi_setprops($message, $props);
Loading history...
2149
		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

2149
		/** @scrutinizer ignore-call */ 
2150
  mapi_message_modifyrecipients($message, MODRECIP_ADD, [$recip]);
Loading history...
2150
		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

2150
		/** @scrutinizer ignore-call */ 
2151
  mapi_savechanges($message);
Loading history...
2151
		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

2151
		/** @scrutinizer ignore-call */ 
2152
  mapi_message_submitmessage($message);
Loading history...
2152
	}
2153
2154
	/**
2155
	 * Function which finds items in calendar based on globalId and cleanGlobalId.
2156
	 *
2157
	 * @param string $goid             GlobalID(0x3) of item
2158
	 * @param mixed  $calendar         MAPI_folder of user (optional)
2159
	 * @param bool   $useCleanGlobalId if true then search should be performed on cleanGlobalId(0x23) else globalId(0x3)
2160
	 *
2161
	 * @return mixed
2162
	 */
2163
	public function findCalendarItems($goid, $calendar = false, $useCleanGlobalId = false) {
2164
		if ($calendar === false) {
2165
			// Open the Calendar
2166
			$calendar = $this->openDefaultCalendar();
2167
		}
2168
2169
		// Find the item by restricting all items to the correct ID
2170
		$restrict = [
2171
			RES_PROPERTY,
2172
			[
2173
				RELOP => RELOP_EQ,
2174
				ULPROPTAG => ($useCleanGlobalId === true ? $this->proptags['goid2'] : $this->proptags['goid']),
2175
				VALUE => $goid,
2176
			],
2177
		];
2178
2179
		$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

2179
		$calendarcontents = /** @scrutinizer ignore-call */ mapi_folder_getcontentstable($calendar);
Loading history...
2180
2181
		$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

2181
		$rows = /** @scrutinizer ignore-call */ mapi_table_queryallrows($calendarcontents, [PR_ENTRYID], $restrict);
Loading history...
2182
2183
		if (empty($rows)) {
2184
			return;
2185
		}
2186
2187
		$calendaritems = [];
2188
2189
		// In principle, there should only be one row, but we'll handle them all just in case
2190
		foreach ($rows as $row) {
2191
			$calendaritems[] = $row[PR_ENTRYID];
2192
		}
2193
2194
		return $calendaritems;
2195
	}
2196
2197
	// Returns TRUE if both entryid's are equal. Equality is defined by both entryid's pointing at the
2198
	// same SMTP address when converted to SMTP
2199
	public function compareABEntryIDs($entryid1, $entryid2): bool {
2200
		// If the session was not passed, just do a 'normal' compare.
2201
		if (!$this->session) {
2202
			return $entryid1 == $entryid2;
2203
		}
2204
2205
		$smtp1 = $this->getSMTPAddress($entryid1);
2206
		$smtp2 = $this->getSMTPAddress($entryid2);
2207
2208
		if ($smtp1 == $smtp2) {
2209
			return true;
2210
		}
2211
2212
		return false;
2213
	}
2214
2215
	// Gets the SMTP address of the passed addressbook entryid
2216
	public function getSMTPAddress($entryid) {
2217
		if (!$this->session) {
2218
			return false;
2219
		}
2220
2221
		try {
2222
			$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

2222
			$ab = /** @scrutinizer ignore-call */ mapi_openaddressbook($this->session);
Loading history...
2223
			$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

2223
			$abitem = /** @scrutinizer ignore-call */ mapi_ab_openentry($ab, $entryid);
Loading history...
2224
2225
			if (!$abitem) {
2226
				return '';
2227
			}
2228
		}
2229
		catch (MAPIException $e) {
2230
			return '';
2231
		}
2232
2233
		$props = mapi_getprops($abitem, [PR_ADDRTYPE, PR_EMAIL_ADDRESS, PR_SMTP_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_ADDRTYPE 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

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

2260
		$storeProps = /** @scrutinizer ignore-call */ mapi_getprops($store, [PR_MAILBOX_OWNER_ENTRYID, PR_USER_ENTRYID]);
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 constant PR_USER_ENTRYID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
2261
2262
		$ownerEntryId = false;
2263
		if (isset($storeProps[PR_USER_ENTRYID]) && $storeProps[PR_USER_ENTRYID]) {
2264
			$ownerEntryId = $storeProps[PR_USER_ENTRYID];
2265
		}
2266
2267
		if (isset($storeProps[PR_MAILBOX_OWNER_ENTRYID]) && $storeProps[PR_MAILBOX_OWNER_ENTRYID] && !$fallbackToLoggedInUser) {
2268
			$ownerEntryId = $storeProps[PR_MAILBOX_OWNER_ENTRYID];
2269
		}
2270
2271
		if ($ownerEntryId) {
2272
			$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

2272
			$ab = /** @scrutinizer ignore-call */ mapi_openaddressbook($this->session);
Loading history...
2273
2274
			$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

2274
			$zarafaUser = /** @scrutinizer ignore-call */ mapi_ab_openentry($ab, $ownerEntryId);
Loading history...
2275
			if (!$zarafaUser) {
2276
				return false;
2277
			}
2278
2279
			$ownerProps = mapi_getprops($zarafaUser, [PR_ADDRTYPE, PR_DISPLAY_NAME, PR_EMAIL_ADDRESS, PR_SEARCH_KEY]);
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_ADDRTYPE 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...
The constant PR_EMAIL_ADDRESS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
2280
2281
			$addrType = $ownerProps[PR_ADDRTYPE];
2282
			$name = $ownerProps[PR_DISPLAY_NAME];
2283
			$emailAddr = $ownerProps[PR_EMAIL_ADDRESS];
2284
			$searchKey = $ownerProps[PR_SEARCH_KEY];
2285
			$entryId = $ownerEntryId;
2286
2287
			return [$name, $emailAddr, $addrType, $entryId, $searchKey];
2288
		}
2289
2290
		return false;
2291
	}
2292
2293
	// Opens this session's default message store
2294
	public function openDefaultStore() {
2295
		$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

2295
		$storestable = /** @scrutinizer ignore-call */ mapi_getmsgstorestable($this->session);
Loading history...
2296
		$rows = mapi_table_queryallrows($storestable, [PR_ENTRYID, PR_DEFAULT_STORE]);
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

2296
		$rows = /** @scrutinizer ignore-call */ mapi_table_queryallrows($storestable, [PR_ENTRYID, PR_DEFAULT_STORE]);
Loading history...
The constant PR_DEFAULT_STORE was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
2297
2298
		foreach ($rows as $row) {
2299
			if (isset($row[PR_DEFAULT_STORE]) && $row[PR_DEFAULT_STORE]) {
2300
				$entryid = $row[PR_ENTRYID];
2301
				break;
2302
			}
2303
		}
2304
2305
		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...
2306
			return false;
2307
		}
2308
2309
		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

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

2363
		/** @scrutinizer ignore-call */ 
2364
  mapi_savechanges($message);
Loading history...
2364
	}
2365
2366
	/**
2367
	 * Function which returns basedate of an changed occurrence from globalID of meeting request.
2368
	 *
2369
	 * @param string $goid globalID
2370
	 *
2371
	 * @return false|int true if basedate is found else false it not found
2372
	 */
2373
	public function getBasedateFromGlobalID($goid) {
2374
		$hexguid = bin2hex($goid);
2375
		$hexbase = substr($hexguid, 32, 8);
2376
		$day = (int) hexdec(substr($hexbase, 6, 2));
2377
		$month = (int) hexdec(substr($hexbase, 4, 2));
2378
		$year = (int) hexdec(substr($hexbase, 0, 4));
2379
2380
		if ($day && $month && $year) {
2381
			return gmmktime(0, 0, 0, $month, $day, $year);
2382
		}
2383
2384
		return false;
2385
	}
2386
2387
	/**
2388
	 * Function which sets basedate in globalID of changed occurrence which is to be sent.
2389
	 *
2390
	 * @param string $goid     globalID
2391
	 * @param mixed  $basedate of changed occurrence
2392
	 *
2393
	 * @return false|string globalID with basedate in it
2394
	 */
2395
	public function setBasedateInGlobalID($goid, $basedate = false) {
2396
		$hexguid = bin2hex($goid);
2397
		$year = $basedate ? sprintf('%04s', dechex((int) gmdate('Y', $basedate))) : '0000';
2398
		$month = $basedate ? sprintf('%02s', dechex((int) gmdate('m', $basedate))) : '00';
2399
		$day = $basedate ? sprintf('%02s', dechex((int) gmdate('d', $basedate))) : '00';
2400
2401
		return hex2bin(strtoupper(substr($hexguid, 0, 32) . $year . $month . $day . substr($hexguid, 40)));
2402
	}
2403
2404
	/**
2405
	 * Function which replaces attachments with copy_from in copy_to.
2406
	 *
2407
	 * @param mixed $copyFrom       MAPI_message from which attachments are to be copied
2408
	 * @param mixed $copyTo         MAPI_message to which attachment are to be copied
2409
	 * @param bool  $copyExceptions if true then all exceptions should also be sent as attachments
2410
	 */
2411
	public function replaceAttachments($copyFrom, $copyTo, $copyExceptions = true): void {
2412
		/* remove all old attachments */
2413
		$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

2413
		$attachmentTableTo = /** @scrutinizer ignore-call */ mapi_message_getattachmenttable($copyTo);
Loading history...
2414
		if ($attachmentTableTo) {
2415
			$attachments = mapi_table_queryallrows($attachmentTableTo, [PR_ATTACH_NUM, PR_ATTACH_METHOD, PR_EXCEPTION_STARTTIME]);
0 ignored issues
show
The constant PR_EXCEPTION_STARTTIME 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

2415
			$attachments = /** @scrutinizer ignore-call */ mapi_table_queryallrows($attachmentTableTo, [PR_ATTACH_NUM, PR_ATTACH_METHOD, PR_EXCEPTION_STARTTIME]);
Loading history...
The constant PR_ATTACH_NUM 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...
2416
2417
			foreach ($attachments as $attachProps) {
2418
				/* remove exceptions too? */
2419
				if (!$copyExceptions && $attachProps[PR_ATTACH_METHOD] == ATTACH_EMBEDDED_MSG && isset($attachProps[PR_EXCEPTION_STARTTIME])) {
2420
					continue;
2421
				}
2422
				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

2422
				/** @scrutinizer ignore-call */ 
2423
    mapi_message_deleteattach($copyTo, $attachProps[PR_ATTACH_NUM]);
Loading history...
2423
			}
2424
		}
2425
2426
		/* copy new attachments */
2427
		$attachmentTableFrom = mapi_message_getattachmenttable($copyFrom);
2428
		if ($attachmentTableFrom) {
2429
			$attachments = mapi_table_queryallrows($attachmentTableFrom, [PR_ATTACH_NUM, PR_ATTACH_METHOD, PR_EXCEPTION_STARTTIME]);
2430
2431
			foreach ($attachments as $attachProps) {
2432
				if (!$copyExceptions && $attachProps[PR_ATTACH_METHOD] == ATTACH_EMBEDDED_MSG && isset($attachProps[PR_EXCEPTION_STARTTIME])) {
2433
					continue;
2434
				}
2435
2436
				$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

2436
				$attachOld = /** @scrutinizer ignore-call */ mapi_message_openattach($copyFrom, (int) $attachProps[PR_ATTACH_NUM]);
Loading history...
2437
				$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

2437
				$attachNewResourceMsg = /** @scrutinizer ignore-call */ mapi_message_createattach($copyTo);
Loading history...
2438
				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

2438
				/** @scrutinizer ignore-call */ 
2439
    mapi_copyto($attachOld, [], [], $attachNewResourceMsg, 0);
Loading history...
2439
				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

2439
				/** @scrutinizer ignore-call */ 
2440
    mapi_savechanges($attachNewResourceMsg);
Loading history...
2440
			}
2441
		}
2442
	}
2443
2444
	/**
2445
	 * Function which replaces recipients in copyTo with recipients from copyFrom.
2446
	 *
2447
	 * @param mixed $copyFrom   MAPI_message from which recipients are to be copied
2448
	 * @param mixed $copyTo     MAPI_message to which recipients are to be copied
2449
	 * @param bool  $isDelegate indicates whether delegate is processing
2450
	 *                          so don't copy delegate information to recipient table
2451
	 */
2452
	public function replaceRecipients($copyFrom, $copyTo, $isDelegate = false): void {
2453
		$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

2453
		$recipientTable = /** @scrutinizer ignore-call */ mapi_message_getrecipienttable($copyFrom);
Loading history...
2454
2455
		// If delegate, then do not add the delegate in recipients
2456
		if ($isDelegate) {
2457
			$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

2457
			$delegate = /** @scrutinizer ignore-call */ mapi_getprops($copyFrom, [PR_RECEIVED_BY_EMAIL_ADDRESS]);
Loading history...
2458
			$res = [
2459
				RES_PROPERTY,
2460
				[
2461
					RELOP => RELOP_NE,
2462
					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...
2463
					VALUE => [PR_EMAIL_ADDRESS => $delegate[PR_RECEIVED_BY_EMAIL_ADDRESS]],
2464
				],
2465
			];
2466
			$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

2466
			$recipients = /** @scrutinizer ignore-call */ mapi_table_queryallrows($recipientTable, $this->recipprops, $res);
Loading history...
2467
		}
2468
		else {
2469
			$recipients = mapi_table_queryallrows($recipientTable, $this->recipprops);
2470
		}
2471
2472
		$copyToRecipientTable = mapi_message_getrecipienttable($copyTo);
2473
		$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...
2474
2475
		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

2475
		/** @scrutinizer ignore-call */ 
2476
  mapi_message_modifyrecipients($copyTo, MODRECIP_REMOVE, $copyToRecipientRows);
Loading history...
2476
		mapi_message_modifyrecipients($copyTo, MODRECIP_ADD, $recipients);
2477
	}
2478
2479
	/**
2480
	 * Function creates meeting item in resource's calendar.
2481
	 *
2482
	 * @param resource $message  MAPI_message which is to create in resource's calendar
2483
	 * @param bool     $cancel   cancel meeting
2484
	 * @param mixed    $prefix   prefix for subject of meeting
2485
	 * @param mixed    $basedate
2486
	 *
2487
	 * @return (mixed|resource)[][]
2488
	 *
2489
	 * @psalm-return list<array{store: resource, folder: mixed, msg: mixed}>
2490
	 */
2491
	public function bookResources($message, $cancel, $prefix, $basedate = false): array {
2492
		if (!$this->enableDirectBooking) {
2493
			return [];
2494
		}
2495
2496
		// Get the properties of the message
2497
		$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

2497
		$messageprops = /** @scrutinizer ignore-call */ mapi_getprops($message);
Loading history...
2498
2499
		if ($basedate) {
2500
			$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...
2501
2502
			$messageprops[$this->proptags['goid']] = $this->setBasedateInGlobalID($recurrItemProps[$this->proptags['goid']], $basedate);
2503
			$messageprops[$this->proptags['goid2']] = $recurrItemProps[$this->proptags['goid2']];
2504
2505
			// Delete properties which are not needed.
2506
			$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_ATTACHMENT_HIDDEN 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_ATTACH_METHOD 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_ATTACHMENT_LINKID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
2507
			foreach ($deleteProps as $propID) {
2508
				if (isset($messageprops[$propID])) {
2509
					unset($messageprops[$propID]);
2510
				}
2511
			}
2512
2513
			if (isset($messageprops[$this->proptags['recurring']])) {
2514
				$messageprops[$this->proptags['recurring']] = false;
2515
			}
2516
2517
			// Set Outlook properties
2518
			$messageprops[$this->proptags['clipstart']] = $messageprops[$this->proptags['startdate']];
2519
			$messageprops[$this->proptags['clipend']] = $messageprops[$this->proptags['duedate']];
2520
			$messageprops[$this->proptags['timezone_data']] = $recurrItemProps[$this->proptags['timezone_data']];
2521
			$messageprops[$this->proptags['timezone']] = $recurrItemProps[$this->proptags['timezone']];
2522
			$messageprops[$this->proptags['attendee_critical_change']] = time();
2523
			$messageprops[$this->proptags['owner_critical_change']] = time();
2524
		}
2525
2526
		// Get resource recipients
2527
		$getResourcesRestriction = [
2528
			RES_PROPERTY,
2529
			[
2530
				RELOP => RELOP_EQ,	// Equals recipient type 3: Resource
2531
				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...
2532
				VALUE => [PR_RECIPIENT_TYPE => MAPI_BCC],
2533
			],
2534
		];
2535
		$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

2535
		$recipienttable = /** @scrutinizer ignore-call */ mapi_message_getrecipienttable($message);
Loading history...
2536
		$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

2536
		$resourceRecipients = /** @scrutinizer ignore-call */ mapi_table_queryallrows($recipienttable, $this->recipprops, $getResourcesRestriction);
Loading history...
2537
2538
		$this->errorSetResource = false;
2539
		$resourceRecipData = [];
2540
2541
		// Put appointment into store resource users
2542
		$i = 0;
2543
		$len = count($resourceRecipients);
2544
		while (!$this->errorSetResource && $i < $len) {
2545
			$userStore = $this->openCustomUserStore($resourceRecipients[$i][PR_ENTRYID]);
2546
2547
			// Open root folder
2548
			$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

2548
			$userRoot = /** @scrutinizer ignore-call */ mapi_msgstore_openentry($userStore, null);
Loading history...
2549
2550
			// Get calendar entryID
2551
			$userRootProps = mapi_getprops($userRoot, [PR_STORE_ENTRYID, PR_IPM_APPOINTMENT_ENTRYID, PR_FREEBUSY_ENTRYIDS]);
0 ignored issues
show
The constant PR_FREEBUSY_ENTRYIDS 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_STORE_ENTRYID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
2552
2553
			// Open Calendar folder
2554
			$accessToFolder = false;
0 ignored issues
show
The assignment to $accessToFolder is dead and can be removed.
Loading history...
2555
2556
			try {
2557
				// @FIXME this checks delegate has access to resource's calendar folder
2558
				// but it should use boss' credentials
2559
2560
				$accessToFolder = $this->checkCalendarWriteAccess($this->store);
2561
				if ($accessToFolder) {
2562
					$calFolder = mapi_msgstore_openentry($userStore, $userRootProps[PR_IPM_APPOINTMENT_ENTRYID]);
2563
				}
2564
			}
2565
			catch (MAPIException $e) {
2566
				$e->setHandled();
2567
				$this->errorSetResource = 1; // No access
2568
			}
2569
2570
			if ($accessToFolder) {
2571
				/**
2572
				 * Get the LocalFreebusy message that contains the properties that
2573
				 * are set to accept or decline resource meeting requests.
2574
				 */
2575
				$localFreebusyMsg = FreeBusy::getLocalFreeBusyMessage($userStore);
2576
				if ($localFreebusyMsg) {
2577
					$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_DISALLOW_RECURRING_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...
2578
2579
					$acceptMeetingRequests = isset($props[PR_SCHDINFO_AUTO_ACCEPT_APPTS]) ? $props[PR_SCHDINFO_AUTO_ACCEPT_APPTS] : false;
2580
					$declineRecurringMeetingRequests = isset($props[PR_SCHDINFO_DISALLOW_RECURRING_APPTS]) ? $props[PR_SCHDINFO_DISALLOW_RECURRING_APPTS] : false;
2581
					$declineConflictingMeetingRequests = isset($props[PR_SCHDINFO_DISALLOW_OVERLAPPING_APPTS]) ? $props[PR_SCHDINFO_DISALLOW_OVERLAPPING_APPTS] : false;
2582
2583
					if (!$acceptMeetingRequests) {
2584
						/*
2585
						 * When a resource has not been set to automatically accept meeting requests,
2586
						 * the meeting request has to be sent to him rather than being put directly into
2587
						 * his calendar. No error should be returned.
2588
						 */
2589
						// $errorSetResource = 2;
2590
						$this->nonAcceptingResources[] = $resourceRecipients[$i];
2591
					}
2592
					else {
2593
						if ($declineRecurringMeetingRequests && !$cancel) {
2594
							// Check if appointment is recurring
2595
							if ($messageprops[$this->proptags['recurring']]) {
2596
								$this->errorSetResource = 3;
2597
							}
2598
						}
2599
						if ($declineConflictingMeetingRequests && !$cancel) {
2600
							// Check for conflicting items
2601
							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...
2602
								$this->errorSetResource = 4; // Conflict
2603
							}
2604
						}
2605
					}
2606
				}
2607
			}
2608
2609
			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...
2610
				/**
2611
				 * First search on GlobalID(0x3)
2612
				 * 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.
2613
				 * If (normal meeting) then GlobalID(0x3) and CleanGlobalID(0x23) are same, so doesn't matter if search is based on GlobalID.
2614
				 */
2615
				$rows = $this->findCalendarItems($messageprops[$this->proptags['goid']], $calFolder);
2616
2617
				/*
2618
				 * If no entry is found then
2619
				 * 1) Resource doesn't have meeting in Calendar. Seriously!!
2620
				 * OR
2621
				 * 2) We were looking for occurrence item but Resource has whole series
2622
				 */
2623
				if (empty($rows)) {
2624
					/**
2625
					 * Now search on CleanGlobalID(0x23) WHY???
2626
					 * Because we are looking recurring item.
2627
					 *
2628
					 * Possible results of this search
2629
					 * 1) If Resource was booked for more than one occurrences then this search will return all those occurrence because search is perform on CleanGlobalID
2630
					 * 2) If Resource was booked for whole series then it should return series.
2631
					 */
2632
					$rows = $this->findCalendarItems($messageprops[$this->proptags['goid2']], $calFolder, true);
2633
2634
					$newResourceMsg = false;
2635
					if (!empty($rows)) {
2636
						// Since we are looking for recurring item, open every result and check for 'recurring' property.
2637
						foreach ($rows as $row) {
2638
							$ResourceMsg = mapi_msgstore_openentry($userStore, $row);
2639
							$ResourceMsgProps = mapi_getprops($ResourceMsg, [$this->proptags['recurring']]);
2640
2641
							if (isset($ResourceMsgProps[$this->proptags['recurring']]) && $ResourceMsgProps[$this->proptags['recurring']]) {
2642
								$newResourceMsg = $ResourceMsg;
2643
								break;
2644
							}
2645
						}
2646
					}
2647
2648
					// Still no results found. I giveup, create new message.
2649
					if (!$newResourceMsg) {
2650
						$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

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

2755
					/** @scrutinizer ignore-call */ 
2756
     mapi_setprops($newResourceMsg, $messageprops);
Loading history...
2756
2757
					// Copy attachments
2758
					$this->replaceAttachments($message, $newResourceMsg);
2759
2760
					// Copy all recipients too
2761
					$this->replaceRecipients($message, $newResourceMsg);
2762
2763
					// Now add organizer also to recipient table
2764
					$recips = [];
2765
					$this->addOrganizer($messageprops, $recips);
2766
2767
					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

2767
					/** @scrutinizer ignore-call */ 
2768
     mapi_message_modifyrecipients($newResourceMsg, MODRECIP_ADD, $recips);
Loading history...
2768
				}
2769
2770
				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

2770
				/** @scrutinizer ignore-call */ 
2771
    mapi_savechanges($newResourceMsg);
Loading history...
2771
2772
				$resourceRecipData[] = [
2773
					'store' => $userStore,
2774
					'folder' => $calFolder,
2775
					'msg' => $newResourceMsg,
2776
				];
2777
				$this->includesResources = true;
2778
			}
2779
			else {
2780
				/*
2781
				 * If no other errors occurred and you have no access to the
2782
				 * folder of the resource, throw an error=1.
2783
				 */
2784
				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...
2785
					$this->errorSetResource = 1;
2786
				}
2787
2788
				for ($j = 0, $len = count($resourceRecipData); $j < $len; ++$j) {
2789
					// Get the EntryID
2790
					$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

2790
					$props = /** @scrutinizer ignore-call */ mapi_message_getprops($resourceRecipData[$j]['msg']);
Loading history...
2791
2792
					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

2792
					/** @scrutinizer ignore-call */ 
2793
     mapi_folder_deletemessages($resourceRecipData[$j]['folder'], [$props[PR_ENTRYID]], DELETE_HARD_DELETE);
Loading history...
2793
				}
2794
				$this->recipientDisplayname = $resourceRecipients[$i][PR_DISPLAY_NAME];
2795
			}
2796
			++$i;
2797
		}
2798
2799
		/*
2800
		 * Set the BCC-recipients (resources) tackstatus to accepted.
2801
		 */
2802
		// Get resource recipients
2803
		$getResourcesRestriction = [
2804
			RES_PROPERTY,
2805
			[
2806
				RELOP => RELOP_EQ,	// Equals recipient type 3: Resource
2807
				ULPROPTAG => PR_RECIPIENT_TYPE,
2808
				VALUE => [PR_RECIPIENT_TYPE => MAPI_BCC],
2809
			],
2810
		];
2811
		$recipienttable = mapi_message_getrecipienttable($message);
2812
		$resourceRecipients = mapi_table_queryallrows($recipienttable, $this->recipprops, $getResourcesRestriction);
2813
		if (!empty($resourceRecipients)) {
2814
			// Set Tracking status of resource recipients to olResponseAccepted (3)
2815
			for ($i = 0, $len = count($resourceRecipients); $i < $len; ++$i) {
2816
				$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...
2817
				$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...
2818
			}
2819
			mapi_message_modifyrecipients($message, MODRECIP_MODIFY, $resourceRecipients);
2820
		}
2821
2822
		return $resourceRecipData;
2823
	}
2824
2825
	/**
2826
	 * Function which save an exception into recurring item.
2827
	 *
2828
	 * @param resource $recurringItem  reference to MAPI_message of recurring item
2829
	 * @param resource $occurrenceItem reference to MAPI_message of occurrence
2830
	 * @param string   $basedate       basedate of occurrence
2831
	 * @param bool     $move           if true then occurrence item is deleted
2832
	 * @param bool     $tentative      true if user has tentatively accepted it or false if user has accepted it
2833
	 * @param bool     $userAction     true if user has manually responded to meeting request
2834
	 * @param resource $store          user store
2835
	 * @param bool     $isDelegate     true if delegate is processing this meeting request
2836
	 */
2837
	public function acceptException(&$recurringItem, &$occurrenceItem, $basedate, $move, $tentative, $userAction, $store, $isDelegate = false): void {
2838
		$recurr = new Recurrence($store, $recurringItem);
2839
2840
		// Copy properties from meeting request
2841
		$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

2841
		$exception_props = /** @scrutinizer ignore-call */ mapi_getprops($occurrenceItem);
Loading history...
2842
2843
		// Copy recipients list
2844
		$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

2844
		$reciptable = /** @scrutinizer ignore-call */ mapi_message_getrecipienttable($occurrenceItem);
Loading history...
2845
		// If delegate, then do not add the delegate in recipients
2846
		if ($isDelegate) {
2847
			$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...
2848
			$res = [
2849
				RES_PROPERTY,
2850
				[
2851
					RELOP => RELOP_NE,
2852
					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...
2853
					VALUE => [PR_EMAIL_ADDRESS => $delegate[PR_RECEIVED_BY_EMAIL_ADDRESS]],
2854
				],
2855
			];
2856
			$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

2856
			$recips = /** @scrutinizer ignore-call */ mapi_table_queryallrows($reciptable, $this->recipprops, $res);
Loading history...
2857
		}
2858
		else {
2859
			$recips = mapi_table_queryallrows($reciptable, $this->recipprops);
2860
		}
2861
2862
		// add owner to recipient table
2863
		$this->addOrganizer($exception_props, $recips, true);
2864
2865
		// add delegator to meetings
2866
		if ($isDelegate) {
2867
			$this->addDelegator($exception_props, $recips);
2868
		}
2869
2870
		$exception_props[$this->proptags['meetingstatus']] = olMeetingReceived;
2871
		$exception_props[$this->proptags['responsestatus']] = $userAction ? ($tentative ? olResponseTentative : olResponseAccepted) : olResponseNotResponded;
2872
2873
		if (isset($exception_props[$this->proptags['intendedbusystatus']])) {
2874
			if ($tentative && $exception_props[$this->proptags['intendedbusystatus']] !== fbFree) {
2875
				$exception_props[$this->proptags['busystatus']] = fbTentative;
2876
			}
2877
			else {
2878
				$exception_props[$this->proptags['busystatus']] = $exception_props[$this->proptags['intendedbusystatus']];
2879
			}
2880
		// we already have intendedbusystatus value in $exception_props so no need to copy it
2881
		}
2882
		else {
2883
			$exception_props[$this->proptags['busystatus']] = $tentative ? fbTentative : fbBusy;
2884
		}
2885
2886
		if ($userAction) {
2887
			$addrInfo = $this->getOwnerAddress($this->store);
2888
2889
			// if user has responded then set replytime and name
2890
			$exception_props[$this->proptags['replytime']] = time();
2891
			if (!empty($addrInfo)) {
2892
				$exception_props[$this->proptags['apptreplyname']] = $addrInfo[0];
2893
			}
2894
		}
2895
2896
		if ($recurr->isException($basedate)) {
2897
			$recurr->modifyException($exception_props, $basedate, $recips, $occurrenceItem);
2898
		}
2899
		else {
2900
			$recurr->createException($exception_props, $basedate, false, $recips, $occurrenceItem);
2901
		}
2902
2903
		// Move the occurrenceItem to the waste basket
2904
		if ($move) {
2905
			$wastebasket = $this->openDefaultWastebasket($this->openDefaultStore());
2906
			$sourcefolder = mapi_msgstore_openentry($store, $exception_props[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_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

2906
			$sourcefolder = /** @scrutinizer ignore-call */ mapi_msgstore_openentry($store, $exception_props[PR_PARENT_ENTRYID]);
Loading history...
2907
			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

2907
			/** @scrutinizer ignore-call */ 
2908
   mapi_folder_copymessages($sourcefolder, [$exception_props[PR_ENTRYID]], $wastebasket, MESSAGE_MOVE);
Loading history...
2908
		}
2909
2910
		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

2910
		/** @scrutinizer ignore-call */ 
2911
  mapi_savechanges($recurringItem);
Loading history...
2911
	}
2912
2913
	/**
2914
	 * Function which merges an exception mapi message to recurring message.
2915
	 * This will be used when we receive recurring meeting request and we already have an exception message
2916
	 * of same meeting in calendar and we need to remove that exception message and add it to attachment table
2917
	 * of recurring meeting.
2918
	 *
2919
	 * @param resource $recurringItem  reference to MAPI_message of recurring item
2920
	 * @param resource $occurrenceItem reference to MAPI_message of occurrence
2921
	 * @param mixed    $basedate       basedate of occurrence
2922
	 * @param resource $store          user store
2923
	 */
2924
	public function mergeException(&$recurringItem, &$occurrenceItem, $basedate, $store): void {
2925
		$recurr = new Recurrence($store, $recurringItem);
2926
2927
		// Copy properties from meeting request
2928
		$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

2928
		$exception_props = /** @scrutinizer ignore-call */ mapi_getprops($occurrenceItem);
Loading history...
2929
2930
		// Get recipient list from message and add it to exception attachment
2931
		$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

2931
		$reciptable = /** @scrutinizer ignore-call */ mapi_message_getrecipienttable($occurrenceItem);
Loading history...
2932
		$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

2932
		$recips = /** @scrutinizer ignore-call */ mapi_table_queryallrows($reciptable, $this->recipprops);
Loading history...
2933
2934
		if ($recurr->isException($basedate)) {
2935
			$recurr->modifyException($exception_props, $basedate, $recips, $occurrenceItem);
2936
		}
2937
		else {
2938
			$recurr->createException($exception_props, $basedate, false, $recips, $occurrenceItem);
2939
		}
2940
2941
		// Move the occurrenceItem to the waste basket
2942
		$wastebasket = $this->openDefaultWastebasket($this->openDefaultStore());
2943
		$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

2943
		$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...
2944
		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

2944
		/** @scrutinizer ignore-call */ 
2945
  mapi_folder_copymessages($sourcefolder, [$exception_props[PR_ENTRYID]], $wastebasket, MESSAGE_MOVE);
Loading history...
2945
2946
		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

2946
		/** @scrutinizer ignore-call */ 
2947
  mapi_savechanges($recurringItem);
Loading history...
2947
	}
2948
2949
	/**
2950
	 * Function which submits meeting request based on arguments passed to it.
2951
	 *
2952
	 * @param resource $message        MAPI_message whose meeting request is to be sent
2953
	 * @param bool     $cancel         if true send request, else send cancellation
2954
	 * @param mixed    $prefix         subject prefix
2955
	 * @param mixed    $basedate       basedate for an occurrence
2956
	 * @param mixed    $recurObject    recurrence object of mr
2957
	 * @param bool     $copyExceptions When sending update mail for recurring item then we don't send exceptions in attachments
2958
	 * @param mixed    $modifiedRecips
2959
	 * @param mixed    $deletedRecips
2960
	 */
2961
	public function submitMeetingRequest($message, $cancel, $prefix, $basedate = false, $recurObject = false, $copyExceptions = true, $modifiedRecips = false, $deletedRecips = false): void {
2962
		$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

2962
		$newmessageprops = $messageprops = /** @scrutinizer ignore-call */ mapi_getprops($this->message);
Loading history...
2963
		$new = $this->createOutgoingMessage();
2964
2965
		// Copy the entire message into the new meeting request message
2966
		if ($basedate) {
2967
			// messageprops contains properties of whole recurring series
2968
			// and newmessageprops contains properties of exception item
2969
			$newmessageprops = mapi_getprops($message);
2970
2971
			// Ensure that the correct basedate is set in the new message
2972
			$newmessageprops[$this->proptags['basedate']] = $basedate;
2973
2974
			// Set isRecurring to false, because this is an exception
2975
			$newmessageprops[$this->proptags['recurring']] = false;
2976
2977
			// set LID_IS_EXCEPTION to true
2978
			$newmessageprops[$this->proptags['is_exception']] = true;
2979
2980
			// Set to high importance
2981
			if ($cancel) {
2982
				$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...
2983
			}
2984
2985
			// Set startdate and enddate of exception
2986
			if ($cancel && $recurObject) {
2987
				$newmessageprops[$this->proptags['startdate']] = $recurObject->getOccurrenceStart($basedate);
2988
				$newmessageprops[$this->proptags['duedate']] = $recurObject->getOccurrenceEnd($basedate);
2989
			}
2990
2991
			// Set basedate in guid (0x3)
2992
			$newmessageprops[$this->proptags['goid']] = $this->setBasedateInGlobalID($messageprops[$this->proptags['goid2']], $basedate);
2993
			$newmessageprops[$this->proptags['goid2']] = $messageprops[$this->proptags['goid2']];
2994
			$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...
2995
2996
			// Get deleted recipiets from exception msg
2997
			$restriction = [
2998
				RES_AND,
2999
				[
3000
					[
3001
						RES_BITMASK,
3002
						[
3003
							ULTYPE => BMR_NEZ,
3004
							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...
3005
							ULMASK => recipExceptionalDeleted,
3006
						],
3007
					],
3008
					[
3009
						RES_BITMASK,
3010
						[
3011
							ULTYPE => BMR_EQZ,
3012
							ULPROPTAG => PR_RECIPIENT_FLAGS,
3013
							ULMASK => recipOrganizer,
3014
						],
3015
					],
3016
				],
3017
			];
3018
3019
			// In direct-booking mode, we don't need to send cancellations to resources
3020
			if ($this->enableDirectBooking) {
3021
				$restriction[1][] = [
3022
					RES_PROPERTY,
3023
					[
3024
						RELOP => RELOP_NE,	// Does not equal recipient type: MAPI_BCC (Resource)
3025
						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...
3026
						VALUE => [PR_RECIPIENT_TYPE => MAPI_BCC],
3027
					],
3028
				];
3029
			}
3030
3031
			$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

3031
			$recipienttable = /** @scrutinizer ignore-call */ mapi_message_getrecipienttable($message);
Loading history...
3032
			$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

3032
			$recipients = /** @scrutinizer ignore-call */ mapi_table_queryallrows($recipienttable, $this->recipprops, $restriction);
Loading history...
3033
3034
			if (!$deletedRecips) {
3035
				$deletedRecips = array_merge([], $recipients);
3036
			}
3037
			else {
3038
				$deletedRecips = array_merge($deletedRecips, $recipients);
3039
			}
3040
		}
3041
3042
		// Remove the PR_ICON_INDEX as it is not needed in the sent message.
3043
		$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...
3044
		$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...
3045
3046
		// PR_START_DATE and PR_END_DATE will be used by outlook to show the position in the calendar
3047
		$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...
3048
		$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...
3049
3050
		// Set updatecounter/AppointmentSequenceNumber
3051
		// get the value of latest updatecounter for the whole series and use it
3052
		$newmessageprops[$this->proptags['updatecounter']] = $messageprops[$this->proptags['last_updatecounter']];
3053
3054
		$meetingTimeInfo = $this->getMeetingTimeInfo();
3055
3056
		if ($meetingTimeInfo) {
3057
			// Needs to unset PR_HTML and PR_RTF_COMPRESSED props
3058
			// because while canceling meeting requests with edit text
3059
			// will override the PR_BODY because body value is not consistent with
3060
			// PR_HTML and PR_RTF_COMPRESSED value so in this case PR_RTF_COMPRESSED will
3061
			// get priority which override the PR_BODY value.
3062
			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...
3063
3064
			$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...
3065
		}
3066
3067
		// Send all recurrence info in mail, if this is a recurrence meeting.
3068
		if (isset($messageprops[$this->proptags['recurring']]) && $messageprops[$this->proptags['recurring']]) {
3069
			if (!empty($messageprops[$this->proptags['recurring_pattern']])) {
3070
				$newmessageprops[$this->proptags['recurring_pattern']] = $messageprops[$this->proptags['recurring_pattern']];
3071
			}
3072
			$newmessageprops[$this->proptags['recurrence_data']] = $messageprops[$this->proptags['recurrence_data']];
3073
			$newmessageprops[$this->proptags['timezone_data']] = $messageprops[$this->proptags['timezone_data']];
3074
			$newmessageprops[$this->proptags['timezone']] = $messageprops[$this->proptags['timezone']];
3075
3076
			if ($recurObject) {
3077
				$this->generateRecurDates($recurObject, $messageprops, $newmessageprops);
3078
			}
3079
		}
3080
3081
		if (isset($newmessageprops[$this->proptags['counter_proposal']])) {
3082
			unset($newmessageprops[$this->proptags['counter_proposal']]);
3083
		}
3084
3085
		// Prefix the subject if needed
3086
		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...
3087
			$newmessageprops[PR_SUBJECT] = $prefix . $newmessageprops[PR_SUBJECT];
3088
		}
3089
3090
		if (isset($newmessageprops[$this->proptags['categories']]) &&
3091
			!empty($newmessageprops[$this->proptags['categories']])) {
3092
			unset($newmessageprops[$this->proptags['categories']]);
3093
		}
3094
		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

3094
		/** @scrutinizer ignore-call */ 
3095
  mapi_setprops($new, $newmessageprops);
Loading history...
3095
3096
		// Copy attachments
3097
		$this->replaceAttachments($message, $new, $copyExceptions);
3098
3099
		// Retrieve only those recipient who should receive this meeting request.
3100
		$stripResourcesRestriction = [
3101
			RES_AND,
3102
			[
3103
				[
3104
					RES_BITMASK,
3105
					[
3106
						ULTYPE => BMR_EQZ,
3107
						ULPROPTAG => PR_RECIPIENT_FLAGS,
3108
						ULMASK => recipExceptionalDeleted,
3109
					],
3110
				],
3111
				[
3112
					RES_BITMASK,
3113
					[
3114
						ULTYPE => BMR_EQZ,
3115
						ULPROPTAG => PR_RECIPIENT_FLAGS,
3116
						ULMASK => recipOrganizer,
3117
					],
3118
				],
3119
			],
3120
		];
3121
3122
		// In direct-booking mode, resources do not receive a meeting request
3123
		if ($this->enableDirectBooking) {
3124
			$stripResourcesRestriction[1][] = [
3125
				RES_PROPERTY,
3126
				[
3127
					RELOP => RELOP_NE,	// Does not equal recipient type: MAPI_BCC (Resource)
3128
					ULPROPTAG => PR_RECIPIENT_TYPE,
3129
					VALUE => [PR_RECIPIENT_TYPE => MAPI_BCC],
3130
				],
3131
			];
3132
		}
3133
3134
		// If no recipients were explicitly provided, we will send the update to all
3135
		// recipients from the meeting.
3136
		if ($modifiedRecips === false) {
3137
			$recipienttable = mapi_message_getrecipienttable($message);
3138
			$modifiedRecips = mapi_table_queryallrows($recipienttable, $this->recipprops, $stripResourcesRestriction);
3139
3140
			if ($basedate && empty($modifiedRecips)) {
3141
				// Retrieve full list
3142
				$recipienttable = mapi_message_getrecipienttable($this->message);
3143
				$modifiedRecips = mapi_table_queryallrows($recipienttable, $this->recipprops);
3144
3145
				// Save recipients in exceptions
3146
				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

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

3189
			/** @scrutinizer ignore-call */ 
3190
   mapi_savechanges($new);
Loading history...
3190
3191
			// Submit message to non-resource recipients
3192
			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

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

3318
		$outgoing = /** @scrutinizer ignore-call */ mapi_folder_createmessage($outbox);
Loading history...
3319
3320
		// check if $store is set and it is not equal to $defaultStore (means its the delegation case)
3321
		if ($store !== false) {
3322
			$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

3322
			$storeProps = /** @scrutinizer ignore-call */ mapi_getprops($store, [PR_ENTRYID]);
Loading history...
3323
			$userStoreProps = mapi_getprops($userStore, [PR_ENTRYID]);
3324
3325
			// @FIXME use entryid comparison functions here
3326
			if ($storeProps[PR_ENTRYID] !== $userStoreProps[PR_ENTRYID]) {
3327
				// get the delegator properties and set it into outgoing mail
3328
				$delegatorDetails = $this->getOwnerAddress($store, false);
3329
3330
				if (!empty($delegatorDetails)) {
3331
					list($ownername, $owneremailaddr, $owneraddrtype, $ownerentryid, $ownersearchkey) = $delegatorDetails;
3332
					$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...
3333
					$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...
3334
					$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...
3335
					$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...
3336
					$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...
3337
				}
3338
3339
				// get the delegate properties and set it into outgoing mail
3340
				$delegateDetails = $this->getOwnerAddress($userStore, false);
3341
3342
				if (!empty($delegateDetails)) {
3343
					list($ownername, $owneremailaddr, $owneraddrtype, $ownerentryid, $ownersearchkey) = $delegateDetails;
3344
					$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...
3345
					$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...
3346
					$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...
3347
					$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...
3348
					$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...
3349
				}
3350
			}
3351
		}
3352
		else {
3353
			// normal user is sending mail, so both set of properties will be same
3354
			$userDetails = $this->getOwnerAddress($userStore);
3355
3356
			if (!empty($userDetails)) {
3357
				list($ownername, $owneremailaddr, $owneraddrtype, $ownerentryid, $ownersearchkey) = $userDetails;
3358
				$sentprops[PR_SENT_REPRESENTING_EMAIL_ADDRESS] = $owneremailaddr;
3359
				$sentprops[PR_SENT_REPRESENTING_NAME] = $ownername;
3360
				$sentprops[PR_SENT_REPRESENTING_ADDRTYPE] = $owneraddrtype;
3361
				$sentprops[PR_SENT_REPRESENTING_ENTRYID] = $ownerentryid;
3362
				$sentprops[PR_SENT_REPRESENTING_SEARCH_KEY] = $ownersearchkey;
3363
3364
				$sentprops[PR_SENDER_EMAIL_ADDRESS] = $owneremailaddr;
3365
				$sentprops[PR_SENDER_NAME] = $ownername;
3366
				$sentprops[PR_SENDER_ADDRTYPE] = $owneraddrtype;
3367
				$sentprops[PR_SENDER_ENTRYID] = $ownerentryid;
3368
				$sentprops[PR_SENDER_SEARCH_KEY] = $ownersearchkey;
3369
			}
3370
		}
3371
3372
		$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...
3373
3374
		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

3374
		/** @scrutinizer ignore-call */ 
3375
  mapi_setprops($outgoing, $sentprops);
Loading history...
3375
3376
		return $outgoing;
3377
	}
3378
3379
	/**
3380
	 * Function which checks that meeting in attendee's calendar is already updated
3381
	 * and we are checking an old meeting request. This function also will update property
3382
	 * meetingtype to indicate that its out of date meeting request.
3383
	 *
3384
	 * @return bool true if meeting request is outofdate else false if it is new
3385
	 */
3386
	public function isMeetingOutOfDate() {
3387
		$result = false;
3388
3389
		$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

3389
		$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...
3390
3391
		if (!$this->isMeetingRequest($props[PR_MESSAGE_CLASS])) {
3392
			return $result;
3393
		}
3394
3395
		if (isset($props[$this->proptags['meetingtype']]) && ($props[$this->proptags['meetingtype']] & mtgOutOfDate) == mtgOutOfDate) {
3396
			return true;
3397
		}
3398
3399
		// get the basedate to check for exception
3400
		$basedate = $this->getBasedateFromGlobalID($props[$this->proptags['goid']]);
3401
3402
		$calendarItem = $this->getCorrespondentCalendarItem(true);
3403
3404
		// if basedate is provided and we could not find the item then it could be that we are checking
3405
		// an exception so get the exception and check it
3406
		if ($basedate !== false && $calendarItem !== false) {
3407
			$exception = $this->getExceptionItem($calendarItem, $basedate);
3408
3409
			if ($exception !== false) {
0 ignored issues
show
The condition $exception !== false is always true.
Loading history...
3410
				// we are able to find the exception compare with it
3411
				$calendarItem = $exception;
3412
			}
3413
			// we are not able to find exception, could mean that a significant change has occurred on series
3414
			// and it deleted all exceptions, so compare with series
3415
			// $calendarItem already contains reference to series
3416
		}
3417
3418
		if ($calendarItem !== false) {
3419
			$calendarItemProps = mapi_getprops($calendarItem, [
3420
				$this->proptags['owner_critical_change'],
3421
				$this->proptags['updatecounter'],
3422
			]);
3423
3424
			$updateCounter = (isset($calendarItemProps[$this->proptags['updatecounter']]) && $props[$this->proptags['updatecounter']] < $calendarItemProps[$this->proptags['updatecounter']]);
3425
3426
			$criticalChange = (isset($calendarItemProps[$this->proptags['owner_critical_change']]) && $props[$this->proptags['owner_critical_change']] < $calendarItemProps[$this->proptags['owner_critical_change']]);
3427
3428
			if ($updateCounter || $criticalChange) {
3429
				// meeting request is out of date, set properties to indicate this
3430
				mapi_setprops($this->message, [$this->proptags['meetingtype'] => mtgOutOfDate, PR_ICON_INDEX => 1033]);
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

3430
				/** @scrutinizer ignore-call */ 
3431
    mapi_setprops($this->message, [$this->proptags['meetingtype'] => mtgOutOfDate, PR_ICON_INDEX => 1033]);
Loading history...
The constant PR_ICON_INDEX was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
3431
				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

3431
				/** @scrutinizer ignore-call */ 
3432
    mapi_savechanges($this->message);
Loading history...
3432
3433
				$result = true;
3434
			}
3435
		}
3436
3437
		return $result;
3438
	}
3439
3440
	/**
3441
	 * Function which checks that if we have received a meeting response for an updated meeting in organizer's calendar.
3442
	 *
3443
	 * @param mixed $basedate basedate of the exception if we want to compare with exception
3444
	 *
3445
	 * @return bool true if meeting request is updated later
3446
	 */
3447
	public function isMeetingUpdated($basedate = false) {
3448
		$result = false;
3449
3450
		$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

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

3513
					$message = /** @scrutinizer ignore-call */ mapi_attach_openobj($attach, MAPI_MODIFY);
Loading history...
3514
				}
3515
			}
3516
		}
3517
		else {
3518
			// use normal message or recurring series message
3519
			$message = $this->message;
3520
		}
3521
3522
		if (!$message) {
3523
			return;
3524
		}
3525
3526
		$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

3526
		$newProps = /** @scrutinizer ignore-call */ mapi_getprops($message, [$this->proptags['startdate'], $this->proptags['duedate'], $this->proptags['updatecounter']]);
Loading history...
3527
3528
		// Check whether message is updated or not.
3529
		if (isset($newProps[$this->proptags['updatecounter']]) && $newProps[$this->proptags['updatecounter']] == 0) {
3530
			return;
3531
		}
3532
3533
		if (($newProps[$this->proptags['startdate']] != $oldProps[$this->proptags['startdate']]) ||
3534
				($newProps[$this->proptags['duedate']] != $oldProps[$this->proptags['duedate']]) ||
3535
				$isRecurrenceChanged) {
3536
			$this->clearRecipientResponse($message);
3537
3538
			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

3538
			/** @scrutinizer ignore-call */ 
3539
   mapi_setprops($message, [$this->proptags['owner_critical_change'] => time()]);
Loading history...
3539
3540
			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

3540
			/** @scrutinizer ignore-call */ 
3541
   mapi_savechanges($message);
Loading history...
3541
			if ($attach) { // Also save attachment Object.
3542
				mapi_savechanges($attach);
3543
			}
3544
		}
3545
	}
3546
3547
	/**
3548
	 * Clear responses of all attendees who have replied in past.
3549
	 *
3550
	 * @param resource $message on which responses should be cleared
3551
	 */
3552
	public function clearRecipientResponse($message): void {
3553
		$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

3553
		$recipTable = /** @scrutinizer ignore-call */ mapi_message_getrecipienttable($message);
Loading history...
3554
		$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

3554
		$recipsRows = /** @scrutinizer ignore-call */ mapi_table_queryallrows($recipTable, $this->recipprops);
Loading history...
3555
3556
		foreach ($recipsRows as $recipient) {
3557
			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...
3558
				// Recipient is attendee, set the trackstatus to 'Not Responded'
3559
				$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...
3560
			}
3561
			else {
3562
				// Recipient is organizer, this is not possible, but for safety
3563
				// it is best to clear the trackstatus for him as well by setting
3564
				// the trackstatus to 'Organized'.
3565
				$recipient[PR_RECIPIENT_TRACKSTATUS] = olRecipientTrackStatusNone;
3566
			}
3567
			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

3567
			/** @scrutinizer ignore-call */ 
3568
   mapi_message_modifyrecipients($message, MODRECIP_MODIFY, [$recipient]);
Loading history...
3568
		}
3569
	}
3570
3571
	/**
3572
	 * Function returns correspondent calendar item attached with the meeting request/response/cancellation.
3573
	 * This will only check for actual MAPIMessages in calendar folder, so if a meeting request is
3574
	 * for exception then this function will return recurring series for that meeting request
3575
	 * after that you need to use getExceptionItem function to get exception item that will be
3576
	 * fetched from the attachment table of recurring series MAPIMessage.
3577
	 *
3578
	 * @param bool $open boolean to indicate the function should return entryid or MAPIMessage. Defaults to true.
3579
	 *
3580
	 * @return bool|resource resource of calendar item
3581
	 */
3582
	public function getCorrespondentCalendarItem($open = true) {
3583
		$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

3583
		$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...
3584
3585
		if (!$this->isMeetingRequest($props[PR_MESSAGE_CLASS]) && !$this->isMeetingRequestResponse($props[PR_MESSAGE_CLASS]) && !$this->isMeetingCancellation($props[PR_MESSAGE_CLASS])) {
3586
			// can work only with meeting requests/responses/cancellations
3587
			return false;
3588
		}
3589
3590
		// there is no goid - no items can be found - aborting
3591
		if (empty($props[$this->proptags['goid']])) {
3592
			return false;
3593
		}
3594
		$globalId = $props[$this->proptags['goid']];
3595
3596
		// If Delegate is processing Meeting Request/Response for Delegator then retrieve Delegator's store and calendar.
3597
		if (isset($props[PR_RCVD_REPRESENTING_ENTRYID])) {
3598
			$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...
3599
3600
			$store = $delegatorStore['store'];
3601
			$calFolder = $delegatorStore[PR_IPM_APPOINTMENT_ENTRYID];
3602
		}
3603
		else {
3604
			$store = $this->store;
3605
			$calFolder = $this->openDefaultCalendar();
3606
		}
3607
3608
		$basedate = $this->getBasedateFromGlobalID($globalId);
3609
3610
		/**
3611
		 * First search for any appointments which correspond to the $globalId,
3612
		 * this can be the entire series (if the Meeting Request refers to the
3613
		 * entire series), or an particular Occurrence (if the meeting Request
3614
		 * contains a basedate).
3615
		 *
3616
		 * If we cannot find a corresponding item, and the $globalId contains
3617
		 * a $basedate, it might imply that a new exception will have to be
3618
		 * created for a series which is present in the calendar, we can look
3619
		 * that one up by searching for the $cleanGlobalId.
3620
		 */
3621
		$entryids = $this->findCalendarItems($globalId, $calFolder);
3622
		if ($basedate !== false && empty($entryids)) {
3623
			// only search if a goid2 is available
3624
			if (!empty($props[$this->proptags['goid2']])) {
3625
				$cleanGlobalId = $props[$this->proptags['goid2']];
3626
				$entryids = $this->findCalendarItems($cleanGlobalId, $calFolder, true);
3627
			}
3628
		}
3629
3630
		// there should be only one item returned
3631
		if (!empty($entryids) && count($entryids) === 1) {
3632
			// return only entryid
3633
			if ($open === false) {
3634
				return $entryids[0];
3635
			}
3636
3637
			// open calendar item and return it
3638
			if ($store) {
3639
				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

3639
				return /** @scrutinizer ignore-call */ mapi_msgstore_openentry($store, $entryids[0]);
Loading history...
3640
			}
3641
		}
3642
3643
		// no items found in calendar
3644
		return false;
3645
	}
3646
3647
	/**
3648
	 * Function returns exception item based on the basedate passed.
3649
	 *
3650
	 * @param mixed $recurringMessage Resource of Recurring meeting from calendar
3651
	 * @param mixed $basedate         basedate of exception that needs to be returned
3652
	 * @param mixed $store            store that contains the recurring calendar item
3653
	 *
3654
	 * @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...
3655
	 */
3656
	public function getExceptionItem($recurringMessage, $basedate, $store = false) {
3657
		$occurItem = false;
3658
3659
		$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

3659
		$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...
3660
3661
		// check if the passed item is recurring series
3662
		if (isset($props[$this->proptags['recurring']]) && $props[$this->proptags['recurring']] !== false) {
3663
			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...
3664
		}
3665
3666
		if ($store === false) {
3667
			// If Delegate is processing Meeting Request/Response for Delegator then retrieve Delegator's store and calendar.
3668
			if (isset($props[PR_RCVD_REPRESENTING_ENTRYID])) {
3669
				$delegatorStore = $this->getDelegatorStore($props[PR_RCVD_REPRESENTING_ENTRYID]);
3670
				$store = $delegatorStore['store'];
3671
			}
3672
			else {
3673
				$store = $this->store;
3674
			}
3675
		}
3676
3677
		$recurr = new Recurrence($store, $recurringMessage);
3678
		$attach = $recurr->getExceptionAttachment($basedate);
3679
		if ($attach) {
3680
			$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

3680
			$occurItem = /** @scrutinizer ignore-call */ mapi_attach_openobj($attach);
Loading history...
3681
		}
3682
3683
		return $occurItem;
3684
	}
3685
3686
	/**
3687
	 * Function which checks whether received meeting request is either conflicting with other appointments or not.
3688
	 *
3689
	 * @param false|resource $message
3690
	 * @param false|resource $userStore
3691
	 * @param mixed          $calFolder calendar folder for conflict checking
3692
	 *
3693
	 * @return bool|int
3694
	 *
3695
	 * @psalm-return bool|int<1, max>
3696
	 */
3697
	public function isMeetingConflicting($message = false, $userStore = false, $calFolder = false) {
3698
		$returnValue = false;
3699
		$noOfInstances = 0;
3700
3701
		if ($message === false) {
3702
			$message = $this->message;
3703
		}
3704
3705
		$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

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

3911
		$calendarItemProps = /** @scrutinizer ignore-call */ mapi_getprops($calendarItem);
Loading history...
3912
		$recurrence = new Recurrence($store, $calendarItem);
3913
3914
		// Retrieve all occurrences(max: 30 occurrence because recurrence can also be set as 'no end date')
3915
		$items = $recurrence->getItems($calendarItemProps[$this->proptags['clipstart']], $calendarItemProps[$this->proptags['clipend']] * (24 * 24 * 60), 30);
3916
		$localCategories = [];
3917
3918
		foreach ($items as $item) {
3919
			$recurrenceItems = $recurrence->getCalendarItems($store, $calFolder, $item[$this->proptags['startdate']], $item[$this->proptags['duedate']], [$this->proptags['goid'], $this->proptags['busystatus'], $this->proptags['categories']]);
3920
			foreach ($recurrenceItems as $recurrenceItem) {
3921
				// Check if occurrence is exception then get the local categories of that occurrence.
3922
				if (isset($recurrenceItem[$this->proptags['goid']]) && $recurrenceItem[$this->proptags['goid']] == $calendarItemProps[$this->proptags['goid']]) {
3923
					$exceptionAttach = $recurrence->getExceptionAttachment($recurrenceItem['basedate']);
3924
3925
					if ($exceptionAttach) {
3926
						$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

3926
						$exception = /** @scrutinizer ignore-call */ mapi_attach_openobj($exceptionAttach, 0);
Loading history...
3927
						$exceptionProps = mapi_getprops($exception, [$this->proptags['categories']]);
3928
						if (isset($exceptionProps[$this->proptags['categories']])) {
3929
							$localCategories[$recurrenceItem['basedate']] = $exceptionProps[$this->proptags['categories']];
3930
						}
3931
					}
3932
				}
3933
			}
3934
		}
3935
3936
		return $localCategories;
3937
	}
3938
3939
	/**
3940
	 * Helper function which is use to apply local categories on respective occurrences.
3941
	 *
3942
	 * @param mixed $calendarItem    meeting request item
3943
	 * @param mixed $store           store containing calendar folder
3944
	 * @param array $localCategories array contains basedate and array of categories
3945
	 */
3946
	public function applyLocalCategories($calendarItem, $store, $localCategories): void {
3947
		$calendarItemProps = mapi_getprops($calendarItem, [PR_PARENT_ENTRYID, 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

3947
		$calendarItemProps = /** @scrutinizer ignore-call */ mapi_getprops($calendarItem, [PR_PARENT_ENTRYID, PR_ENTRYID]);
Loading history...
The constant PR_PARENT_ENTRYID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
3948
		$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

3948
		$message = /** @scrutinizer ignore-call */ mapi_msgstore_openentry($store, $calendarItemProps[PR_ENTRYID]);
Loading history...
3949
		$recurrence = new Recurrence($store, $message);
3950
3951
		// Check for all occurrence if it is exception then modify the exception by setting up categories,
3952
		// Otherwise create new exception with categories.
3953
		foreach ($localCategories as $key => $value) {
3954
			if ($recurrence->isException($key)) {
3955
				$recurrence->modifyException([$this->proptags['categories'] => $value], $key);
3956
			}
3957
			else {
3958
				$recurrence->createException([$this->proptags['categories'] => $value], $key, false);
3959
			}
3960
			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

3960
			/** @scrutinizer ignore-call */ 
3961
   mapi_savechanges($message);
Loading history...
3961
		}
3962
	}
3963
}
3964