Test Failed
Push — master ( cd42b5...841446 )
by
unknown
16:44 queued 06:09
created

ReminderListModule   A

Complexity

Total Complexity 31

Size/Duplication

Total Lines 283
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 137
c 1
b 0
f 0
dl 0
loc 283
rs 9.92
wmc 31

5 Methods

Rating   Name   Duplication   Size   Complexity  
A execute() 0 18 5
A getReminderFolderEntryId() 0 9 2
A __construct() 0 4 1
C createReminderFolder() 0 101 13
C getReminders() 0 133 10
1
<?php
2
3
	/**
4
	 * Reminder Module.
5
	 *
6
	 * TODO: add description
7
	 */
8
	class ReminderListModule extends ListModule {
9
		/**
10
		 * Constructor.
11
		 *
12
		 * @param int   $id   unique id
13
		 * @param array $data list of all actions
14
		 */
15
		public function __construct($id, $data) {
16
			parent::__construct($id, $data);
17
18
			$this->properties = $GLOBALS["properties"]->getReminderProperties();
19
		}
20
21
		public function execute() {
22
			foreach ($this->data as $actionType => $action) {
23
				$store = $GLOBALS["mapisession"]->getDefaultMessageStore();
24
				$this->reminderEntryId = $this->getReminderFolderEntryId($store);
0 ignored issues
show
Bug Best Practice introduced by
The property reminderEntryId does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
25
26
				if (isset($actionType)) {
27
					try {
28
						switch ($actionType) {
29
							case "list":
30
								$this->getReminders();
31
								break;
32
33
							default:
34
								$this->handleUnknownActionType($actionType);
35
						}
36
					}
37
					catch (MAPIException $e) {
38
						$this->processException($e, $actionType, $store, null, null, $action);
39
					}
40
				}
41
			}
42
		}
43
44
		public function getReminderFolderEntryId($store) {
45
			$root = mapi_msgstore_openentry($store, null);
46
			$rootProps = mapi_getprops($root, [PR_REM_ONLINE_ENTRYID]);
47
			if (isset($rootProps[PR_REM_ONLINE_ENTRYID])) {
48
				return $rootProps[PR_REM_ONLINE_ENTRYID];
49
			}
50
51
			// Reminder folder didn't exist, create one
52
			return $this->createReminderFolder($store);
53
		}
54
55
		public function createReminderFolder($store) {
56
			$storeProps = mapi_getprops($store, [PR_IPM_OUTBOX_ENTRYID, PR_IPM_WASTEBASKET_ENTRYID, PR_IPM_SUBTREE_ENTRYID]);
57
			$root = mapi_msgstore_openentry($store, null);
58
			$rootProps = mapi_getprops($root, [PR_ADDITIONAL_REN_ENTRYIDS, PR_IPM_DRAFTS_ENTRYID]);
59
60
			$folders = [];
61
			if (isset($storeProps[PR_IPM_WASTEBASKET_ENTRYID])) {
62
				$folders[] = $storeProps[PR_IPM_WASTEBASKET_ENTRYID];
63
			}
64
			if (isset($rootProps[PR_ADDITIONAL_REN_ENTRYIDS]) && !empty($rootProps[PR_ADDITIONAL_REN_ENTRYIDS][4])) {
65
				$folders[] = $rootProps[PR_ADDITIONAL_REN_ENTRYIDS][4];
66
			} // junk mail
67
			if (isset($rootProps[PR_IPM_DRAFTS_ENTRYID])) {
68
				$folders[] = $rootProps[PR_IPM_DRAFTS_ENTRYID];
69
			}
70
			if (isset($storeProps[PR_IPM_OUTBOX_ENTRYID])) {
71
				$folders[] = $storeProps[PR_IPM_OUTBOX_ENTRYID];
72
			}
73
			if (isset($rootProps[PR_ADDITIONAL_REN_ENTRYIDS]) && !empty($rootProps[PR_ADDITIONAL_REN_ENTRYIDS][0])) {
74
				$folders[] = $rootProps[PR_ADDITIONAL_REN_ENTRYIDS][0];
75
			} // conflicts
76
			if (isset($rootProps[PR_ADDITIONAL_REN_ENTRYIDS]) && !empty($rootProps[PR_ADDITIONAL_REN_ENTRYIDS][2])) {
77
				$folders[] = $rootProps[PR_ADDITIONAL_REN_ENTRYIDS][2];
78
			} // local failures
79
			if (isset($rootProps[PR_ADDITIONAL_REN_ENTRYIDS]) && !empty($rootProps[PR_ADDITIONAL_REN_ENTRYIDS][1])) {
80
				$folders[] = $rootProps[PR_ADDITIONAL_REN_ENTRYIDS][1];
81
			} // sync issues
82
83
			$folderRestriction = [];
84
			foreach ($folders as $folder) {
85
				$folderRestriction[] = [RES_PROPERTY,
86
					[
87
						RELOP => RELOP_NE,
88
						ULPROPTAG => $this->properties["parent_entryid"],
89
						VALUE => [$this->properties["parent_entryid"] => $folder],
90
					],
91
				];
92
			}
93
94
			$res =
95
				[RES_AND,
96
					[
97
						[RES_AND,
98
							$folderRestriction,
99
						],
100
						[RES_AND,
101
							[
102
								[RES_NOT,
103
									[
104
										[RES_AND,
105
											[
106
												[RES_EXIST,
107
													[
108
														ULPROPTAG => $this->properties["message_class"],
109
													],
110
												],
111
												[RES_CONTENT,
112
													[
113
														FUZZYLEVEL => FL_PREFIX,
114
														ULPROPTAG => $this->properties["message_class"],
115
														VALUE => [$this->properties["message_class"] => "IPM.Schedule"],
116
													],
117
												],
118
											],
119
										],
120
									],
121
								],
122
								[RES_BITMASK,
123
									[
124
										ULTYPE => BMR_EQZ,
125
										ULPROPTAG => $this->properties["message_flags"],
126
										ULMASK => MSGFLAG_SUBMIT,
127
									],
128
								],
129
								[RES_OR,
130
									[
131
										[RES_PROPERTY,
132
											[
133
												RELOP => RELOP_EQ,
134
												ULPROPTAG => $this->properties["reminder"],
135
												VALUE => [$this->properties["reminder"] => true],
136
											],
137
										],
138
									],
139
								],
140
							],
141
						],
142
					],
143
				];
144
145
			$folder = mapi_folder_createfolder($root, _("Reminders"), "", OPEN_IF_EXISTS, FOLDER_SEARCH);
146
			mapi_setprops($folder, [PR_CONTAINER_CLASS => "Outlook.Reminder"]);
147
			mapi_savechanges($folder);
148
149
			mapi_folder_setsearchcriteria($folder, $res, [$storeProps[PR_IPM_SUBTREE_ENTRYID]], RECURSIVE_SEARCH);
150
			$folderProps = mapi_getprops($folder, [PR_ENTRYID]);
151
152
			mapi_setprops($root, [PR_REM_ONLINE_ENTRYID => $folderProps[PR_ENTRYID]]);
153
			mapi_savechanges($root);
154
155
			return $folderProps[PR_ENTRYID];
156
		}
157
158
		public function getReminders() {
159
			$data = [];
160
161
			$store = $GLOBALS["mapisession"]->getDefaultMessageStore();
162
163
			$restriction = [RES_AND,
164
				[
165
					[RES_PROPERTY,
166
						[
167
							RELOP => RELOP_LT,
168
							ULPROPTAG => $this->properties["flagdueby"],
169
							VALUE => [$this->properties["flagdueby"] => time()],
170
						],
171
					],
172
					[RES_PROPERTY,
173
						[
174
							RELOP => RELOP_EQ,
175
							ULPROPTAG => $this->properties["reminder"],
176
							VALUE => true,
177
						],
178
					],
179
					[RES_PROPERTY,
180
						[
181
							RELOP => RELOP_NE,
182
							ULPROPTAG => $this->properties["message_class"],
183
							VALUE => "IPM.TaskRequest",
184
						],
185
					],
186
					[RES_PROPERTY,
187
						[
188
							RELOP => RELOP_NE,
189
							ULPROPTAG => $this->properties["message_class"],
190
							VALUE => "IPM.TaskRequest.Cancel",
191
						],
192
					],
193
					[RES_PROPERTY,
194
						[
195
							RELOP => RELOP_NE,
196
							ULPROPTAG => $this->properties["message_class"],
197
							VALUE => "IPM.TaskRequest.Accept",
198
						],
199
					],
200
					[RES_PROPERTY,
201
						[
202
							RELOP => RELOP_NE,
203
							ULPROPTAG => $this->properties["message_class"],
204
							VALUE => "IPM.TaskRequest.Update",
205
						],
206
					],
207
					[RES_PROPERTY,
208
						[
209
							RELOP => RELOP_NE,
210
							ULPROPTAG => $this->properties["message_class"],
211
							VALUE => "IPM.TaskRequest.Complete",
212
						],
213
					],
214
				],
215
			];
216
217
			try {
218
				$reminderfolder = mapi_msgstore_openentry($store, $this->reminderEntryId);
219
			}
220
			catch (MAPIException $e) {
221
				// if the reminder folder does not exist, try to recreate it.
222
				if ($e->getCode() == MAPI_E_NOT_FOUND) {
223
					$e->setHandled();
224
225
					$this->reminderEntryId = $this->createReminderFolder($store);
0 ignored issues
show
Bug Best Practice introduced by
The property reminderEntryId does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
226
					$reminderfolder = mapi_msgstore_openentry($store, $this->reminderEntryId);
227
				}
228
			}
229
230
			$remindertable = mapi_folder_getcontentstable($reminderfolder, MAPI_DEFERRED_ERRORS);
231
			if (!$remindertable) {
232
				return false;
233
			}
234
235
			mapi_table_restrict($remindertable, $restriction, TBL_BATCH);
236
			mapi_table_sort($remindertable, [$this->properties["flagdueby"] => TABLE_SORT_DESCEND], TBL_BATCH);
237
238
			// reminder store hold only 99 records as
239
			// we show 99 notification on client side.
240
			$rows = mapi_table_queryrows($remindertable, $this->properties, 0, MAX_NUM_REMINDERS);
241
			$data["item"] = [];
242
243
			foreach ($rows as $row) {
244
				if (isset($row[$this->properties["appointment_recurring"]]) && $row[$this->properties["appointment_recurring"]]) {
245
					$recur = new Recurrence($store, $row);
246
247
					/**
248
					 * FlagDueBy == PidLidReminderSignalTime.
249
					 * FlagDueBy handles whether we should be showing the item; if now() is after FlagDueBy, then we should show a reminder
250
					 * for this recurrence. However, the item we will show is either the last passed occurrence (overdue), or the next occurrence, depending
251
					 * on whether we have reached the next occurrence yet (the reminder_time of the next item is ignored).
252
					 *
253
					 * The way we handle this is to get all occurrences between the 'flagdueby' moment and the current time. This will
254
					 * yield N items (may be a lot of it was not dismissed for a long time). We can then take the last item in this list, and this is the item
255
					 * we will show to the user. The idea here is:
256
					 *
257
					 * The item we want to show is the last item in that list (new occurrences that have started uptil now should override old ones)
258
					 *
259
					 * Add the reminder_minutes (default 15 minutes for calendar, 0 for tasks) to check over the gap between FlagDueBy and the start time of the
260
					 * occurrence, if "now" would be in between these values.
261
					 */
262
					$remindertimeinseconds = $row[$this->properties["reminder_minutes"]] * 60;
263
					$occurrences = $recur->getItems($row[$this->properties["flagdueby"]], time() + ($remindertimeinseconds), 0, true);
0 ignored issues
show
Bug introduced by
time() + $remindertimeinseconds of type integer is incompatible with the type date expected by parameter $end of BaseRecurrence::getItems(). ( Ignorable by Annotation )

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

263
					$occurrences = $recur->getItems($row[$this->properties["flagdueby"]], /** @scrutinizer ignore-type */ time() + ($remindertimeinseconds), 0, true);
Loading history...
264
265
					if (empty($occurrences)) {
266
						continue;
267
					}
268
269
					// More than one occurrence, use the last one instead of the first one after flagdueby
270
					$occ = $occurrences[count($occurrences) - 1];
271
272
					// Bydefault, on occurrence reminder is true but if reminder value is set to false then we don't send popup reminder for this occurrence
273
					if (!(isset($occ[$this->properties['reminder']]) && $occ[$this->properties['reminder']] == 0)) {
274
						$row[$this->properties["reminder_time"]] = $occ[$this->properties["appointment_startdate"]];
275
						$row[$this->properties["appointment_startdate"]] = $occ[$this->properties["appointment_startdate"]];
276
						$row[$this->properties["appointment_enddate"]] = $occ[$this->properties["appointment_startdate"]];
277
					}
278
				}
279
280
				// Add the non-bogus rows
281
				array_push($data["item"], Conversion::mapMAPI2XML($this->properties, $row));
282
			}
283
284
			$this->addActionData("list", $data);
285
			$GLOBALS["bus"]->addData($this->getResponseData());
286
287
			// Trigger the newmailnotifier
288
			$GLOBALS["bus"]->notify(REQUEST_ENTRYID, HIERARCHY_UPDATE, ['', '']);
289
290
			return true;
291
		}
292
	}
293