Passed
Push — master ( 47e36c...1b8f90 )
by
unknown
06:00 queued 18s
created

IndexSqlite::try_insert_content()   C

Complexity

Conditions 16
Paths 87

Size

Total Lines 51
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 16
eloc 26
c 2
b 0
f 0
nc 87
nop 9
dl 0
loc 51
rs 5.5666

How to fix   Long Method    Complexity    Many Parameters   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
define('PRIVATE_FID_ROOT', 0x1);
4
5
define('PR_FOLDER_ID', 0x67480014);
6
define('PR_MID', 0x674A0014);
7
define('PR_CHANGE_NUMBER', 0x67A40014);
8
9
class IndexSqlite extends SQLite3 {
10
	private $username;
11
	private $stmt;
12
	private $count;
13
	private $store;
14
	private $session;
15
	private $hide_attachments_proptag;
0 ignored issues
show
introduced by
The private property $hide_attachments_proptag is not used, and could be removed.
Loading history...
16
17
	private static function get_gc_value($eid) {
18
		$r0 = ($eid >> 56) & 0xFF;
19
		$r1 = ($eid >> 48) & 0xFF;
20
		$r2 = ($eid >> 40) & 0xFF;
21
		$r3 = ($eid >> 32) & 0xFF;
22
		$r4 = ($eid >> 24) & 0xFF;
23
		$r5 = ($eid >> 16) & 0xFF;
24
		$value = $r0 | ($r1 << 8) | ($r2 << 16) | ($r3 << 24) | ($r4 << 32) | ($r5 << 40);
25
26
		return $value;
27
	}
28
29
	public function __construct($username = null, $session = null, $store = null) {
30
		$this->username = $username ?? $GLOBALS["mapisession"]->getSMTPAddress();
31
		$this->session = $session ?? $GLOBALS["mapisession"]->getSession();
32
		$this->store = $store ?? $GLOBALS["mapisession"]->getDefaultMessageStore();
33
	}
34
35
	private function try_insert_content(
36
		$search_entryid,
37
		$row,
38
		$folder_id,
39
		$recursive,
40
		$message_classes,
41
		$date_start,
42
		$date_end,
43
		$unread,
44
		$has_attachments
45
	) {
46
		// if match condition contains '@', $row['entryid'] will disappear. it seems a bug for php-sqlite
47
		if (strlen($row['entryid']) == 0) {
48
			$results = $this->query("SELECT entryid FROM messages WHERE message_id=" . $row['message_id']);
49
			$row1 = $results->fetchArray(SQLITE3_NUM);
50
			if ($row1) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $row1 of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
51
				$row['entryid'] = $row1[0];
52
			}
53
		}
54
		if (isset($message_classes)) {
55
			$found = false;
56
			foreach ($message_classes as $message_class) {
57
				if (strncasecmp($row['message_class'], $message_class, strlen($message_class)) == 0) {
58
					$found = true;
59
					break;
60
				}
61
			}
62
			if (!$found) {
63
				return;
64
			}
65
		}
66
		if (isset($date_start) && $row['date'] < $date_start) {
67
			return;
68
		}
69
		if (isset($date_end) && $row['date'] > $date_end) {
70
			return;
71
		}
72
		if (isset($unread) && $row['readflag']) {
73
			return;
74
		}
75
		if (isset($has_attachments) && !$row['attach_indexed']) {
76
			return;
77
		}
78
79
		try {
80
			mapi_linkmessage($this->session, $search_entryid, $row['entryid']);
81
		}
82
		catch (Exception $e) {
83
			return;
84
		}
85
		++$this->count;
86
	}
87
88
	private function result_full() {
89
		return $this->count >= MAX_FTS_RESULT_ITEMS;
90
	}
91
92
	public function search(
93
		$search_entryid,
94
		$sender,
95
		$sending,
96
		$recipients,
97
		$subject,
98
		$content,
99
		$attachments,
100
		$others,
101
		$folder_entrid,
102
		$recursive,
103
		$message_classes,
104
		$date_start,
105
		$date_end,
106
		$unread,
107
		$has_attachments
108
	) {
109
		$search_folder = mapi_msgstore_openentry($this->store, $search_entryid);
110
		$tmp_props = mapi_getprops($search_folder, [PR_FOLDER_ID]);
0 ignored issues
show
Unused Code introduced by
The assignment to $tmp_props is dead and can be removed.
Loading history...
111
		if (isset($folder_entrid)) {
112
			try {
113
				$folder = mapi_msgstore_openentry($this->store, $folder_entrid);
114
				if (!$folder) {
115
					return false;
116
				}
117
				$tmp_props = mapi_getprops($folder, [PR_FOLDER_ID]);
118
				if (empty($tmp_props[PR_FOLDER_ID])) {
119
					return false;
120
				}
121
				$folder_id = IndexSqlite::get_gc_value((int) $tmp_props[PR_FOLDER_ID]);
122
			}
123
			catch (Exception $e) {
124
				return false;
125
			}
126
		}
127
		$sql_string = "SELECT message_id, entryid, folder_id, sender, sending, " .
128
			"recipients, subject, content, attachments, message_class, date, attach_indexed, readflag FROM" .
129
			" messages WHERE messages MATCH '";
130
		$this->count = 0;
131
		if (isset($sender) && $sender == $sending && $sending == $recipients && $recipients == $subject &&
132
			$subject == $content && $content == $attachments && $attachments == $others) {
133
			$sql_string .= SQLite3::escapeString($this->quote_words($sender)) . "'";
134
		}
135
		else {
136
			$first = true;
137
			if (isset($sender)) {
138
				if ($first === true) {
0 ignored issues
show
introduced by
The condition $first === true is always true.
Loading history...
139
					$first = false;
140
				}
141
				else {
142
					$sql_string .= " OR ";
143
				}
144
				$sql_string .= 'sender:' . SQLite3::escapeString($this->quote_words($sender));
145
			}
146
			if (isset($sending)) {
147
				if ($first === true) {
148
					$first = false;
149
				}
150
				else {
151
					$sql_string .= " OR ";
152
				}
153
				$sql_string .= 'sending:' . SQLite3::escapeString($this->quote_words($sending));
154
			}
155
			if (isset($recipients)) {
156
				if ($first === true) {
157
					$first = false;
158
				}
159
				else {
160
					$sql_string .= " OR ";
161
				}
162
				$sql_string .= 'recipients:' . SQLite3::escapeString($this->quote_words($recipients));
163
			}
164
			if (isset($subject)) {
165
				if ($first === true) {
166
					$first = false;
167
				}
168
				else {
169
					$sql_string .= " OR ";
170
				}
171
				$sql_string .= 'subject:' . SQLite3::escapeString($this->quote_words($subject));
172
			}
173
			if (isset($content)) {
174
				if ($first === true) {
175
					$first = false;
176
				}
177
				else {
178
					$sql_string .= " OR ";
179
				}
180
				$sql_string .= 'content:' . SQLite3::escapeString($this->quote_words($content));
181
			}
182
			if (isset($attachments)) {
183
				if ($first === true) {
184
					$first = false;
185
				}
186
				else {
187
					$sql_string .= " OR ";
188
				}
189
				$sql_string .= 'attachments:' . SQLite3::escapeString($this->quote_words($attachments));
190
			}
191
			if (isset($others)) {
192
				if ($first === true) {
193
					$first = false;
194
				}
195
				else {
196
					$sql_string .= " OR ";
197
				}
198
				$sql_string .= 'others:' . SQLite3::escapeString($this->quote_words($others));
199
			}
200
			if ($first) {
201
				return false;
202
			}
203
			$sql_string .= "'";
204
		}
205
		$sql_string .= " ORDER BY date DESC LIMIT " . MAX_FTS_RESULT_ITEMS;
206
		$results = $this->query($sql_string);
207
		while (($row = $results->fetchArray(SQLITE3_ASSOC)) && !$this->result_full()) {
208
			$this->try_insert_content(
209
				$search_entryid,
210
				$row,
211
				$folder_id,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $folder_id does not seem to be defined for all execution paths leading up to this point.
Loading history...
212
				$recursive,
213
				$message_classes,
214
				$date_start,
215
				$date_end,
216
				$unread,
217
				$has_attachments
218
			);
219
		}
220
221
		return true;
222
	}
223
224
	private function create() {
225
		mkdir(SQLITE_INDEX_PATH . '/' . $this->username);
226
		chmod(SQLITE_INDEX_PATH . '/' . $this->username, 0770);
227
		$this->open(SQLITE_INDEX_PATH . '/' . $this->username . '/index.sqlite3');
228
		chmod(SQLITE_INDEX_PATH . '/' . $this->username . '/index.sqlite3', 0660);
229
230
		return true;
231
	}
232
233
	public function load() {
234
		if (!is_file(SQLITE_INDEX_PATH . '/' . $this->username . '/index.sqlite3')) {
235
			if ($this->create() === false) {
0 ignored issues
show
introduced by
The condition $this->create() === false is always false.
Loading history...
236
				return false;
237
			}
238
		}
239
		else {
240
			$this->open(SQLITE_INDEX_PATH . '/' . $this->username . '/index.sqlite3');
241
		}
242
		$sql_string = "CREATE TABLE IF NOT EXISTS hierarchy(" .
243
				"folder_id INTEGER PRIMARY KEY," .
244
				"commit_max INTEGER NOT NULL," .
245
				"max_cn INTEGER NOT NULL);\n" .
246
				"CREATE VIRTUAL TABLE IF NOT EXISTS messages USING " .
247
				SQLITE_FTS_ENGINE .
248
				"(sender, sending, recipients, " .
249
				"subject, content, attachments," .
250
				"others, message_id," .
251
				"attach_indexed UNINDEXED," .
252
				"entryid UNINDEXED," .
253
				"change_num UNINDEXED," .
254
				"folder_id UNINDEXED," .
255
				"message_class UNINDEXED," .
256
				"date UNINDEXED, " .
257
				"readflag UNINDEXED, " .
258
				"tokenize=" . SQLITE_FTS_TOKENIZER . ");";
259
		if ($this->exec($sql_string) === false) {
260
			error_log("fail to execute sqlite create table statemente, " . $this->lastErrorMsg());
261
262
			return false;
263
		}
264
265
		// refresh the index sqlite database if configured
266
		return REFRESH_SEARCH_INDEX ? $this->refresh() : true;
267
	}
268
269
	private function refresh() {
270
		$mapping = [
271
			"categories" => "PT_MV_STRING8:PS_PUBLIC_STRINGS:Keywords",
272
			"fileas" => "PT_STRING8:PSETID_Address:0x8005",
273
			"location" => "PT_STRING8:PSETID_Appointment:" . PidLidLocation,
274
			"email1" => "PT_STRING8:PSETID_Address:" . PidLidEmail1EmailAddress,
275
			"emai1_name" => "PT_STRING8:PSETID_Address:" . PidLidEmail1DisplayName,
276
			"email2" => "PT_STRING8:PSETID_Address:" . PidLidEmail2EmailAddress,
277
			"email2_name" => "PT_STRING8:PSETID_Address:" . PidLidEmail2DisplayName,
278
			"email3" => "PT_STRING8:PSETID_Address:" . PidLidEmail3EmailAddress,
279
			"email3_name" => "PT_STRING8:PSETID_Address:" . PidLidEmail3DisplayName,
280
			"home_address" => "PT_STRING8:PSETID_Address:0x801a",
281
			"other_address" => "PT_STRING8:PSETID_Address:0x801c",
282
			"work_address" => "PT_STRING8:PSETID_Address:0x801b",
283
			"task_owner" => "PT_STRING8:PSETID_Task:0x811f",
284
			"companies" => "PT_MV_STRING8:PSETID_Common:0x8539",
285
		];
286
		$properties = getPropIdsFromStrings($this->store, $mapping);
287
		$store_props = mapi_getprops($this->store, [PR_IPM_SUBTREE_ENTRYID]);
288
		$entryid = $store_props[PR_IPM_SUBTREE_ENTRYID];
289
290
		try {
291
			$ipm_subtree = mapi_msgstore_openentry($this->store, $entryid);
292
			$table = mapi_folder_gethierarchytable($ipm_subtree, CONVENIENT_DEPTH);
293
		}
294
		catch (Exception $e) {
295
			error_log("fail to refresh indexing sqlite, cannot open ipmsubstree hierarchy table in " . $this->username . "'s store");
296
297
			return false;
298
		}
299
		$stmt = $this->prepare("SELECT commit_max, max_cn FROM hierarchy WHERE folder_id=:folder_id");
300
		$items = mapi_table_queryallrows($table, [PR_ENTRYID,
301
			PR_FOLDER_ID, PR_FOLDER_TYPE, PR_LOCAL_COMMIT_TIME_MAX, ]);
302
		$hierarchy = [];
303
		$messages = [];
304
		foreach ($items as $item) {
305
			if ($item[PR_FOLDER_TYPE] != FOLDER_GENERIC) {
306
				continue;
307
			}
308
			$max_cn = 0;
309
			$last_cn = 0;
310
			$folder_id = IndexSqlite::get_gc_value((int) $item[PR_FOLDER_ID]);
311
			$stmt->reset();
312
			$stmt->bindValue(":folder_id", $folder_id, SQLITE3_INTEGER);
313
			$ret = $stmt->execute();
314
			$row = $ret->fetchArray(SQLITE3_ASSOC);
315
			if ($row) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $row of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
316
				$max_cn = $row['max_cn'];
317
				$last_cn = $max_cn;
318
				if ($row['commit_max'] == $item[PR_LOCAL_COMMIT_TIME_MAX]) {
319
					continue;
320
				}
321
			}
322
323
			try {
324
				$folder = mapi_msgstore_openentry($this->store, $item[PR_ENTRYID]);
325
				$table = mapi_folder_getcontentstable($folder);
326
				$contents = mapi_table_queryallrows($table, [PR_MID, PR_CHANGE_NUMBER, PR_ENTRYID]);
327
				foreach ($contents as $content) {
328
					$change_num = IndexSqlite::get_gc_value((int) $content[PR_CHANGE_NUMBER]);
329
					if ($change_num > $last_cn) {
330
						if ($change_num > $max_cn) {
331
							$max_cn = $change_num;
332
						}
333
						$messages[] = [IndexSqlite::get_gc_value((int) $content[PR_MID]), $content[PR_ENTRYID]];
334
					}
335
				}
336
			}
337
			catch (Exception $e) {
338
				error_log("fail to refresh indexing sqlite, cannot load contents for folder " . $folder_id . " in " . $this->username . "'s store");
339
340
				return false;
341
			}
342
			$hierarchy[] = [$folder_id, $item[PR_LOCAL_COMMIT_TIME_MAX], $max_cn];
343
		}
344
		$stmt->close();
345
346
		$this->remove($messages);
347
		$this->precompile_insert();
348
		$count = count($messages);
349
		for ($i = 0; $i < $count; ++$i) {
350
			try {
351
				$message = mapi_msgstore_openentry($this->store, $messages[$i][1]);
352
				$this->insert_message($messages[$i][0], $message, $properties);
353
			}
354
			catch (Exception $e) {
355
				error_log("fail to insert message " . $messages[$i][0] . " into index sqlite for " . $this->username);
356
357
				continue;
358
			}
359
		}
360
		$this->finalize();
361
		$this->refresh_hierarchy($hierarchy);
362
363
		return true;
364
	}
365
366
	public function insert_message($message_id, $message, $properties) {
367
		$others_tags = [
368
			PR_DISPLAY_NAME,
369
			PR_DISPLAY_NAME_PREFIX,
370
			PR_HOME_TELEPHONE_NUMBER,
371
			PR_MOBILE_TELEPHONE_NUMBER,
372
			PR_BUSINESS_TELEPHONE_NUMBER,
373
			PR_BUSINESS_FAX_NUMBER,
374
			PR_ASSISTANT_TELEPHONE_NUMBER,
375
			PR_BUSINESS2_TELEPHONE_NUMBER,
376
			PR_CALLBACK_TELEPHONE_NUMBER,
377
			PR_CAR_TELEPHONE_NUMBER,
378
			PR_COMPANY_MAIN_PHONE_NUMBER,
379
			PR_HOME2_TELEPHONE_NUMBER,
380
			PR_HOME_FAX_NUMBER,
381
			PR_OTHER_TELEPHONE_NUMBER,
382
			PR_PAGER_TELEPHONE_NUMBER,
383
			PR_PRIMARY_FAX_NUMBER,
384
			PR_PRIMARY_TELEPHONE_NUMBER,
385
			PR_RADIO_TELEPHONE_NUMBER,
386
			PR_TELEX_NUMBER,
387
			PR_TTYTDD_PHONE_NUMBER,
388
			PR_COMPANY_NAME,
389
			PR_TITLE, ];
390
		$proptags = array_merge(
391
			[PR_ENTRYID,
392
				PR_SENT_REPRESENTING_NAME,
393
				PR_SENT_REPRESENTING_SMTP_ADDRESS,
394
				PR_SUBJECT,
395
				PR_BODY,
396
				PR_HTML,
397
				PR_SENDER_NAME,
398
				PR_SENDER_SMTP_ADDRESS,
399
				PR_INTERNET_CPID,
400
				PR_RTF_COMPRESSED,
401
				PR_CHANGE_NUMBER,
402
				PR_FOLDER_ID,
403
				PR_MESSAGE_CLASS,
404
				PR_MESSAGE_DELIVERY_TIME,
405
				PR_LAST_MODIFICATION_TIME,
406
				PR_MESSAGE_FLAGS, ],
407
			array_values($properties)
408
		);
409
		$proptags = array_merge($proptags, $others_tags);
410
		$propvals = mapi_getprops($message, $proptags);
411
		$entryid = $propvals[PR_ENTRYID];
412
		$table = mapi_message_getrecipienttable($message);
413
		$recips = mapi_table_queryallrows($table, [PR_DISPLAY_NAME, PR_SMTP_ADDRESS]);
414
		$recipients_string = '';
415
		$first = true;
416
		foreach ($recips as $recip) {
417
			if (!$first) {
418
				$recipients_string .= "\n";
419
			}
420
			$first = false;
421
			if (isset($recip[PR_DISPLAY_NAME])) {
422
				$recipients_string .= $recip[PR_DISPLAY_NAME];
423
			}
424
			if (isset($recip[PR_SMTP_ADDRESS])) {
425
				$recipients_string .= "\n" . $recip[PR_SMTP_ADDRESS];
426
			}
427
		}
428
		$table = mapi_message_getattachmenttable($message);
429
		$attachments = mapi_table_queryallrows($table, [PR_ATTACH_LONG_FILENAME]);
430
		$attachments_string = '';
431
		$first = true;
432
		foreach ($attachments as $attach) {
433
			if (!$first) {
434
				$attachments_string .= "\n";
435
			}
436
			if (isset($attach[PR_ATTACH_LONG_FILENAME])) {
437
				$first = false;
438
				$attachments_string .= $attach[PR_ATTACH_LONG_FILENAME];
439
			}
440
		}
441
		$sending = null;
442
		if (isset($propvals[PR_SENT_REPRESENTING_NAME], $propvals[PR_SENT_REPRESENTING_SMTP_ADDRESS])) {
443
			$sending = $propvals[PR_SENT_REPRESENTING_NAME] . "\n" . $propvals[PR_SENT_REPRESENTING_SMTP_ADDRESS];
444
		}
445
		elseif (isset($propvals[PR_SENT_REPRESENTING_NAME])) {
446
			$sending = $propvals[PR_SENT_REPRESENTING_NAME];
447
		}
448
		elseif (isset($propvals[PR_SENT_REPRESENTING_SMTP_ADDRESS])) {
449
			$sending = "\n" . $propvals[PR_SENT_REPRESENTING_SMTP_ADDRESS];
450
		}
451
		$sender = null;
452
		if (isset($propvals[PR_SENDER_NAME], $propvals[PR_SENDER_SMTP_ADDRESS])) {
453
			$sender = $propvals[PR_SENDER_NAME] . "\n" . $propvals[PR_SENDER_SMTP_ADDRESS];
454
		}
455
		elseif (isset($propvals[PR_SENDER_NAME])) {
456
			$sender = $propvals[PR_SENDER_NAME];
457
		}
458
		elseif (isset($propvals[PR_SENDER_SMTP_ADDRESS])) {
459
			$sender = "\n" . $propvals[PR_SENDER_SMTP_ADDRESS];
460
		}
461
		$subject = null;
462
		if (isset($propvals[PR_SUBJECT])) {
463
			$subject = $propvals[PR_SUBJECT];
464
		}
465
		$html = null;
466
		if (isset($propvals[PR_HTML])) {
467
			$cpid = $propvals[PR_INTERNET_CPID];
468
			if (empty($cpid)) {
469
				$cpid = 65001;
470
			}
471
			$html = Conversion::convertCodepageStringToUtf8($cpid, $propvals[PR_HTML]);
472
		}
473
		if (!$html && isset($propvals[PR_RTF_COMPRESSED])) {
474
			$html = mapi_decompressrtf($propvals[PR_RTF_COMPRESSED]);
475
		}
476
		if ($html) {
477
			$body = strip_tags($html);
478
		}
479
		else {
480
			if (isset($propvals[PR_BODY])) {
481
				$body = $propvals[PR_BODY];
482
			}
483
		}
484
		$others = '';
485
		foreach ($properties as $name => $proptag) {
486
			if (isset($propvals[$proptag])) {
487
				if ($name == 'companies' || $name == 'categories') {
488
					$others .= implode("\n", $propvals[$proptag]) . "\n";
489
				}
490
				else {
491
					$others .= $propvals[$proptag] . "\n";
492
				}
493
			}
494
		}
495
		foreach ($others_tags as $proptag) {
496
			if (isset($propvals[$proptag])) {
497
				$others .= $propvals[$proptag] . "\n";
498
			}
499
		}
500
		if (empty($propvals[PR_MESSAGE_DELIVERY_TIME])) {
501
			$last_time = $propvals[PR_LAST_MODIFICATION_TIME];
502
		}
503
		else {
504
			$last_time = $propvals[PR_MESSAGE_DELIVERY_TIME];
505
		}
506
		if (empty($propvals[PR_FOLDER_ID]) ||
507
			empty($propvals[PR_CHANGE_NUMBER]) ||
508
			empty($propvals[PR_MESSAGE_CLASS])) {
509
			return;
510
		}
511
		$readflag = isset($propvals[PR_MESSAGE_FLAGS]) ?
512
			$propvals[PR_MESSAGE_FLAGS] & MSGFLAG_READ : 1;
513
514
		$this->bind_insert(
515
			$sender,
516
			$sending,
517
			$recipients_string,
518
			$subject,
519
			$body,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $body does not seem to be defined for all execution paths leading up to this point.
Loading history...
520
			$attachments_string,
521
			$others,
522
			$message_id,
523
			$entryid,
524
			IndexSqlite::get_gc_value((int) $propvals[PR_CHANGE_NUMBER]),
525
			IndexSqlite::get_gc_value((int) $propvals[PR_FOLDER_ID]),
526
			$propvals[PR_MESSAGE_CLASS],
527
			$last_time,
528
			$readflag
529
		);
530
	}
531
532
	private function precompile_insert() {
533
		$this->stmt = $this->prepare("INSERT INTO messages (sender, sending, recipients, subject, " .
534
			"content, attachments, others, message_id, attach_indexed, entryid, change_num, folder_id," .
535
			" message_class, date, readflag) VALUES (:sender, :sending, :recipients, :subject, :content, " .
536
			":attachments, :others, :message_id, :attach_indexed, :entryid, :change_num, :folder_id, " .
537
			":message_class, :date, :readflag)");
538
		if (!$this->stmt) {
539
			error_log("fail to precompile the insert statement for messages table, " . $this->lastErrorMsg());
540
541
			return false;
542
		}
543
		$this->exec("BEGIN TRANSACTION");
544
545
		return true;
546
	}
547
548
	private function bind_insert(
549
		$sender,
550
		$sending,
551
		$recipients,
552
		$subject,
553
		$content,
554
		$attachments,
555
		$others,
556
		$message_id,
557
		$entryid,
558
		$change_num,
559
		$folder_id,
560
		$message_class,
561
		$date,
562
		$readflag
563
	) {
564
		$this->stmt->clear();
565
		if (isset($sender)) {
566
			$this->stmt->bindValue(":sender", $sender, SQLITE3_TEXT);
567
		}
568
		else {
569
			$this->stmt->bindValue(":sender", $sender, SQLITE3_NULL);
570
		}
571
		if (isset($sending)) {
572
			$this->stmt->bindValue(":sending", $sending, SQLITE3_TEXT);
573
		}
574
		else {
575
			$this->stmt->bindValue(":sending", $sending, SQLITE3_NULL);
576
		}
577
		if (isset($recipients)) {
578
			$this->stmt->bindValue(":recipients", $recipients, SQLITE3_TEXT);
579
		}
580
		else {
581
			$this->stmt->bindValue(":recipients", $recipients, SQLITE3_NULL);
582
		}
583
		if (isset($subject)) {
584
			$this->stmt->bindValue(":subject", $subject, SQLITE3_TEXT);
585
		}
586
		else {
587
			$this->stmt->bindValue(":subject", $subject, SQLITE3_NULL);
588
		}
589
		if (isset($content)) {
590
			$this->stmt->bindValue(":content", $content, SQLITE3_TEXT);
591
		}
592
		else {
593
			$this->stmt->bindValue(":content", $content, SQLITE3_NULL);
594
		}
595
		if (isset($attachments)) {
596
			$this->stmt->bindValue(":attachments", $attachments, SQLITE3_TEXT);
597
		}
598
		else {
599
			$this->stmt->bindValue(":attachments", $attachments, SQLITE3_NULL);
600
		}
601
		if (isset($others)) {
602
			$this->stmt->bindValue(":others", $others, SQLITE3_TEXT);
603
		}
604
		else {
605
			$this->stmt->bindValue(":others", $others, SQLITE3_NULL);
606
		}
607
		$this->stmt->bindValue(":message_id", $message_id, SQLITE3_INTEGER);
608
		if (isset($attachments)) {
609
			$this->stmt->bindValue(":attach_indexed", 0, SQLITE3_INTEGER);
610
		}
611
		else {
612
			$this->stmt->bindValue(":attach_indexed", 1, SQLITE3_INTEGER);
613
		}
614
		$this->stmt->bindValue(":entryid", $entryid, SQLITE3_BLOB);
615
		$this->stmt->bindValue(":change_num", $change_num, SQLITE3_INTEGER);
616
		$this->stmt->bindValue(":folder_id", $folder_id, SQLITE3_INTEGER);
617
		$this->stmt->bindValue(":message_class", $message_class, SQLITE3_TEXT);
618
		$this->stmt->bindValue(":date", $date, SQLITE3_INTEGER);
619
		$this->stmt->bindValue(":readflag", $readflag, SQLITE3_INTEGER);
620
		$this->stmt->execute();
621
	}
622
623
	private function finalize() {
624
		$this->exec("COMMIT TRANSACTION");
625
		$this->stmt->close();
626
		unset($this->stmt);
627
	}
628
629
	private function remove($deletion) {
630
		$stmt = $this->prepare("DELETE FROM messages WHERE message_id=:message_id");
631
		if (!$stmt) {
0 ignored issues
show
introduced by
$stmt is of type SQLite3Stmt, thus it always evaluated to true.
Loading history...
632
			error_log("fail to precompile the delete statement for messages table, " . $this->lastErrorMsg());
633
634
			return false;
635
		}
636
		$this->exec("BEGIN TRANSACTION");
637
		$count = count($deletion);
638
		for ($i = 0; $i < $count; ++$i) {
639
			$stmt->clear();
640
			$stmt->bindValue(":message_id", $deletion[$i][0], SQLITE3_INTEGER);
641
			$stmt->execute();
642
		}
643
		$this->exec("COMMIT TRANSACTION");
644
645
		return true;
646
	}
647
648
	private function refresh_hierarchy($hierarchy) {
649
		$stmt = $this->prepare("REPLACE INTO hierarchy (folder_id, commit_max, max_cn) VALUES (:folder_id, :commit_max, :max_cn)");
650
		$this->exec("BEGIN TRANSACTION");
651
		$count = count($hierarchy);
652
		for ($i = 0; $i < $count; ++$i) {
653
			$stmt->clear();
654
			$stmt->bindValue(":folder_id", $hierarchy[$i][0], SQLITE3_INTEGER);
655
			$stmt->bindValue(":commit_max", $hierarchy[$i][1], SQLITE3_INTEGER);
656
			$stmt->bindValue(":max_cn", $hierarchy[$i][2], SQLITE3_INTEGER);
657
			$stmt->execute();
658
		}
659
		$this->exec("COMMIT TRANSACTION");
660
661
		return true;
662
	}
663
664
	private function quote_words($search_string) {
665
		return '"' . preg_replace("/(\\s+)/", '*" "', trim($search_string)) . '"*';
666
	}
667
}
668