Changeset 5233 in subversion
- Timestamp:
- Sep 18, 2011 5:02:35 AM (20 months ago)
- Location:
- trunk/roundcubemail
- Files:
-
- 20 edited
-
. (modified) (1 prop)
-
CHANGELOG (modified) (2 diffs)
-
SQL/mssql.initial.sql (modified) (3 diffs)
-
SQL/mssql.upgrade.sql (modified) (2 diffs)
-
SQL/mysql.initial.sql (modified) (2 diffs)
-
SQL/mysql.update.sql (modified) (1 diff)
-
SQL/postgres.initial.sql (modified) (2 diffs)
-
SQL/postgres.update.sql (modified) (1 diff)
-
SQL/sqlite.initial.sql (modified) (2 diffs)
-
SQL/sqlite.update.sql (modified) (1 diff)
-
program/include/rcube_imap.php (modified) (4 diffs)
-
program/include/rcube_imap_cache.php (modified) (38 diffs)
-
program/include/rcube_imap_generic.php (modified) (11 diffs)
-
program/js/app.js (modified) (6 diffs)
-
program/steps/mail/check_recent.inc (modified) (1 diff)
-
program/steps/mail/compose.inc (modified) (1 diff)
-
program/steps/mail/func.inc (modified) (4 diffs)
-
program/steps/mail/list.inc (modified) (2 diffs)
-
program/steps/mail/move_del.inc (modified) (1 diff)
-
program/steps/mail/show.inc (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/roundcubemail
- Property svn:mergeinfo changed
/branches/devel-mcache/roundcubemail merged: 5193,5217-5219
- Property svn:mergeinfo changed
-
trunk/roundcubemail/CHANGELOG
r5232 r5233 2 2 =========================== 3 3 4 - Cache synchronization using QRESYNC/CONDSTORE 4 5 - Fix locked folder rename option on servers supporting RFC2086 only (#1488089) 5 6 - Trigger 'new_messages' hook for all checked folders (#1488083) … … 18 19 Added threads data caching 19 20 Flags are stored separately, so flag change doesn't cause DELETE+INSERT, just UPDATE 20 - Partial QRESYNC support21 21 - Improved FETCH response handling 22 22 - Improvements in response tokenization method -
trunk/roundcubemail/SQL/mssql.initial.sql
r5190 r5233 12 12 [mailbox] [varchar] (128) COLLATE Latin1_General_CI_AI NOT NULL , 13 13 [changed] [datetime] NOT NULL , 14 [valid] [char] (1) COLLATE Latin1_General_CI_AI NOT NULL , 14 15 [data] [text] COLLATE Latin1_General_CI_AI NOT NULL 15 16 ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] … … 30 31 [changed] [datetime] NOT NULL , 31 32 [data] [text] COLLATE Latin1_General_CI_AI NOT NULL 32 [seen] [char](1) NOT NULL , 33 [deleted] [char](1) NOT NULL , 34 [answered] [char](1) NOT NULL , 35 [forwarded] [char](1) NOT NULL , 36 [flagged] [char](1) NOT NULL , 37 [mdnsent] [char](1) NOT NULL , 33 [flags] [int](1) NOT NULL , 38 34 ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] 39 35 GO … … 230 226 ALTER TABLE [dbo].[cache_messages] ADD 231 227 CONSTRAINT [DF_cache_messages_changed] DEFAULT (getdate()) FOR [changed] 232 CONSTRAINT [DF_cache_messages_seen] DEFAULT (0) FOR [seen], 233 CONSTRAINT [DF_cache_messages_deleted] DEFAULT (0) FOR [deleted], 234 CONSTRAINT [DF_cache_messages_answered] DEFAULT (0) FOR [answered], 235 CONSTRAINT [DF_cache_messages_forwarded] DEFAULT (0) FOR [forwarded], 236 CONSTRAINT [DF_cache_messages_flagged] DEFAULT (0) FOR [flagged], 237 CONSTRAINT [DF_cache_messages_mdnsent] DEFAULT (0) FOR [mdnsent], 228 CONSTRAINT [DF_cache_messages_flags] DEFAULT (0) FOR [flags], 238 229 GO 239 230 -
trunk/roundcubemail/SQL/mssql.upgrade.sql
r5190 r5233 176 176 [changed] [datetime] NOT NULL , 177 177 [data] [text] COLLATE Latin1_General_CI_AI NOT NULL 178 [seen] [char](1) NOT NULL , 179 [deleted] [char](1) NOT NULL , 180 [answered] [char](1) NOT NULL , 181 [forwarded] [char](1) NOT NULL , 182 [flagged] [char](1) NOT NULL , 183 [mdnsent] [char](1) NOT NULL , 178 [flags] [int] NOT NULL , 184 179 ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] 185 180 GO … … 221 216 222 217 ALTER TABLE [dbo].[cache_messages] ADD 223 CONSTRAINT [DF_cache_messages_changed] DEFAULT (getdate()) FOR [changed] 224 CONSTRAINT [DF_cache_messages_seen] DEFAULT (0) FOR [seen], 225 CONSTRAINT [DF_cache_messages_deleted] DEFAULT (0) FOR [deleted], 226 CONSTRAINT [DF_cache_messages_answered] DEFAULT (0) FOR [answered], 227 CONSTRAINT [DF_cache_messages_forwarded] DEFAULT (0) FOR [forwarded], 228 CONSTRAINT [DF_cache_messages_flagged] DEFAULT (0) FOR [flagged], 229 CONSTRAINT [DF_cache_messages_mdnsent] DEFAULT (0) FOR [mdnsent], 218 CONSTRAINT [DF_cache_messages_changed] DEFAULT (getdate()) FOR [changed], 219 CONSTRAINT [DF_cache_messages_flags] DEFAULT (0) FOR [flags] 230 220 GO 231 221 -
trunk/roundcubemail/SQL/mysql.initial.sql
r5190 r5233 56 56 `mailbox` varchar(255) BINARY NOT NULL, 57 57 `changed` datetime NOT NULL DEFAULT '1000-01-01 00:00:00', 58 `valid` tinyint(1) NOT NULL DEFAULT '0', 58 59 `data` longtext NOT NULL, 59 60 CONSTRAINT `user_id_fk_cache_index` FOREIGN KEY (`user_id`) … … 86 87 `changed` datetime NOT NULL DEFAULT '1000-01-01 00:00:00', 87 88 `data` longtext NOT NULL, 88 `seen` tinyint(1) NOT NULL DEFAULT '0', 89 `deleted` tinyint(1) NOT NULL DEFAULT '0', 90 `answered` tinyint(1) NOT NULL DEFAULT '0', 91 `forwarded` tinyint(1) NOT NULL DEFAULT '0', 92 `flagged` tinyint(1) NOT NULL DEFAULT '0', 93 `mdnsent` tinyint(1) NOT NULL DEFAULT '0', 89 `flags` int(11) NOT NULL DEFAULT '0', 94 90 CONSTRAINT `user_id_fk_cache_messages` FOREIGN KEY (`user_id`) 95 91 REFERENCES `users`(`user_id`) ON DELETE CASCADE ON UPDATE CASCADE, -
trunk/roundcubemail/SQL/mysql.update.sql
r5190 r5233 202 202 `changed` datetime NOT NULL DEFAULT '1000-01-01 00:00:00', 203 203 `data` longtext NOT NULL, 204 `seen` tinyint(1) NOT NULL DEFAULT '0', 205 `deleted` tinyint(1) NOT NULL DEFAULT '0', 206 `answered` tinyint(1) NOT NULL DEFAULT '0', 207 `forwarded` tinyint(1) NOT NULL DEFAULT '0', 208 `flagged` tinyint(1) NOT NULL DEFAULT '0', 209 `mdnsent` tinyint(1) NOT NULL DEFAULT '0', 204 `flags` int(11) NOT NULL DEFAULT '0', 210 205 CONSTRAINT `user_id_fk_cache_messages` FOREIGN KEY (`user_id`) 211 206 REFERENCES `users`(`user_id`) ON DELETE CASCADE ON UPDATE CASCADE, -
trunk/roundcubemail/SQL/postgres.initial.sql
r5190 r5233 198 198 mailbox varchar(255) NOT NULL, 199 199 changed timestamp with time zone DEFAULT now() NOT NULL, 200 valid smallint NOT NULL DEFAULT 0, 200 201 data text NOT NULL, 201 202 PRIMARY KEY (user_id, mailbox) … … 232 233 changed timestamp with time zone DEFAULT now() NOT NULL, 233 234 data text NOT NULL, 234 seen smallint NOT NULL DEFAULT 0, 235 deleted smallint NOT NULL DEFAULT 0, 236 answered smallint NOT NULL DEFAULT 0, 237 forwarded smallint NOT NULL DEFAULT 0, 238 flagged smallint NOT NULL DEFAULT 0, 239 mdnsent smallint NOT NULL DEFAULT 0, 235 flags integer NOT NULL DEFAULT 0, 240 236 PRIMARY KEY (user_id, mailbox, uid) 241 237 ); -
trunk/roundcubemail/SQL/postgres.update.sql
r5190 r5233 160 160 changed timestamp with time zone DEFAULT now() NOT NULL, 161 161 data text NOT NULL, 162 seen smallint NOT NULL DEFAULT 0, 163 deleted smallint NOT NULL DEFAULT 0, 164 answered smallint NOT NULL DEFAULT 0, 165 forwarded smallint NOT NULL DEFAULT 0, 166 flagged smallint NOT NULL DEFAULT 0, 167 mdnsent smallint NOT NULL DEFAULT 0, 162 flags integer NOT NULL DEFAULT 0, 168 163 PRIMARY KEY (user_id, mailbox, uid) 169 164 ); -
trunk/roundcubemail/SQL/sqlite.initial.sql
r5190 r5233 160 160 mailbox varchar(255) NOT NULL, 161 161 changed datetime NOT NULL default '0000-00-00 00:00:00', 162 valid smallint NOT NULL DEFAULT '0', 162 163 data text NOT NULL, 163 164 PRIMARY KEY (user_id, mailbox) … … 194 195 changed datetime NOT NULL default '0000-00-00 00:00:00', 195 196 data text NOT NULL, 196 seen smallint NOT NULL DEFAULT '0', 197 deleted smallint NOT NULL DEFAULT '0', 198 answered smallint NOT NULL DEFAULT '0', 199 forwarded smallint NOT NULL DEFAULT '0', 200 flagged smallint NOT NULL DEFAULT '0', 201 mdnsent smallint NOT NULL DEFAULT '0', 197 flags integer NOT NULL DEFAULT '0', 202 198 PRIMARY KEY (user_id, mailbox, uid) 203 199 ); -
trunk/roundcubemail/SQL/sqlite.update.sql
r5190 r5233 277 277 changed datetime NOT NULL default '0000-00-00 00:00:00', 278 278 data text NOT NULL, 279 seen smallint NOT NULL DEFAULT '0', 280 deleted smallint NOT NULL DEFAULT '0', 281 answered smallint NOT NULL DEFAULT '0', 282 forwarded smallint NOT NULL DEFAULT '0', 283 flagged smallint NOT NULL DEFAULT '0', 284 mdnsent smallint NOT NULL DEFAULT '0', 279 flags integer NOT NULL DEFAULT '0', 285 280 PRIMARY KEY (user_id, mailbox, uid) 286 281 ); -
trunk/roundcubemail/program/include/rcube_imap.php
r5232 r5233 814 814 } 815 815 816 return $this->_list_headers($mailbox, $page, $sort_field, $sort_order, false,$slice);816 return $this->_list_headers($mailbox, $page, $sort_field, $sort_order, $slice); 817 817 } 818 818 … … 1087 1087 if (!empty($parents)) { 1088 1088 $headers[$idx]->parent_uid = end($parents); 1089 if ( !$header->seen)1089 if (empty($header->flags['SEEN'])) 1090 1090 $headers[$parents[0]]->unread_children++; 1091 1091 } … … 3422 3422 if ($this->conn->select($mailbox)) 3423 3423 $this->mailbox = $mailbox; 3424 else 3425 return null; 3424 3426 } 3425 3427 … … 3514 3516 3515 3517 return $options; 3518 } 3519 3520 3521 /** 3522 * Synchronizes messages cache. 3523 * 3524 * @param string $mailbox Folder name 3525 */ 3526 public function mailbox_sync($mailbox) 3527 { 3528 if ($mcache = $this->get_mcache_engine()) { 3529 $mcache->synchronize($mailbox); 3530 } 3516 3531 } 3517 3532 -
trunk/roundcubemail/program/include/rcube_imap_cache.php
r5192 r5233 62 62 private $skip_deleted = false; 63 63 64 public $flag_fields = array('seen', 'deleted', 'answered', 'forwarded', 'flagged', 'mdnsent'); 64 /** 65 * List of known flags. Thanks to this we can handle flag changes 66 * with good performance. Bad thing is we need to know used flags. 67 */ 68 public $flags = array( 69 1 => 'SEEN', // RFC3501 70 2 => 'DELETED', // RFC3501 71 4 => 'ANSWERED', // RFC3501 72 8 => 'FLAGGED', // RFC3501 73 16 => 'DRAFT', // RFC3501 74 32 => 'MDNSENT', // RFC3503 75 64 => 'FORWARDED', // RFC5550 76 128 => 'SUBMITPENDING', // RFC5550 77 256 => 'SUBMITTED', // RFC5550 78 512 => 'JUNK', 79 1024 => 'NONJUNK', 80 2048 => 'LABEL1', 81 4096 => 'LABEL2', 82 8192 => 'LABEL3', 83 16384 => 'LABEL4', 84 32768 => 'LABEL5', 85 ); 65 86 66 87 … … 106 127 107 128 // Seek in internal cache 108 if (array_key_exists('index', $this->icache[$mailbox]) 109 && ($sort_field == 'ANY' || $this->icache[$mailbox]['index']['sort_field'] == $sort_field) 110 ) { 111 if ($this->icache[$mailbox]['index']['sort_order'] == $sort_order) 112 return $this->icache[$mailbox]['index']['result']; 113 else 114 return array_reverse($this->icache[$mailbox]['index']['result'], true); 129 if (array_key_exists('index', $this->icache[$mailbox])) { 130 // The index was fetched from database already, but not validated yet 131 if (!array_key_exists('result', $this->icache[$mailbox]['index'])) { 132 $index = $this->icache[$mailbox]['index']; 133 } 134 // We've got a valid index 135 else if ($sort_field == 'ANY' || $this->icache[$mailbox]['index']['sort_field'] == $sort_field 136 ) { 137 if ($this->icache[$mailbox]['index']['sort_order'] == $sort_order) 138 return $this->icache[$mailbox]['index']['result']; 139 else 140 return array_reverse($this->icache[$mailbox]['index']['result'], true); 141 } 115 142 } 116 143 117 144 // Get index from DB (if DB wasn't already queried) 118 if (empty($ this->icache[$mailbox]['index_queried'])) {145 if (empty($index) && empty($this->icache[$mailbox]['index_queried'])) { 119 146 $index = $this->get_index_row($mailbox); 120 147 … … 124 151 $this->icache[$mailbox]['index_queried'] = true; 125 152 } 126 $data = null; 153 154 $data = null; 127 155 128 156 // @TODO: Think about skipping validation checks. … … 132 160 // and many rcube_imap changes to connect when needed 133 161 134 // Entry exist , check cache status162 // Entry exists, check cache status 135 163 if (!empty($index)) { 136 164 $exists = true; … … 156 184 } 157 185 else { 186 if ($existing) { 187 return null; 188 } 189 else if ($sort_field == 'ANY') { 190 $sort_field = ''; 191 } 192 158 193 // Got it in internal cache, so the row already exist 159 194 $exists = array_key_exists('index', $this->icache[$mailbox]); 160 161 if ($existing) {162 return null;163 }164 else if ($sort_field == 'ANY') {165 $sort_field = '';166 }167 195 } 168 196 … … 171 199 // Get mailbox data (UIDVALIDITY, counters, etc.) for status check 172 200 $mbox_data = $this->imap->mailbox_data($mailbox); 173 $data = array(); 174 175 // Prevent infinite loop. 176 // It happens when rcube_imap::message_index_direct() is called. 177 // There id2uid() is called which will again call get_index() and so on. 178 if (!$sort_field && !$this->skip_deleted) 179 $this->icache['pending_index_update'] = true; 180 181 if ($mbox_data['EXISTS']) { 182 // fetch sorted sequence numbers 183 $data_seq = $this->imap->message_index_direct($mailbox, $sort_field, $sort_order); 184 // fetch UIDs 185 if (!empty($data_seq)) { 186 // Seek in internal cache 187 if (array_key_exists('index', (array)$this->icache[$mailbox])) 188 $data_uid = $this->icache[$mailbox]['index']['result']; 189 else 190 $data_uid = $this->imap->conn->fetchUIDs($mailbox, $data_seq); 191 192 // build index 193 if (!empty($data_uid)) { 194 foreach ($data_seq as $seq) 195 if ($uid = $data_uid[$seq]) 196 $data[$seq] = $uid; 197 } 198 } 199 } 200 201 // Reset internal flags 202 $this->icache['pending_index_update'] = false; 201 $data = $this->get_index_data($mailbox, $sort_field, $sort_order, $mbox_data); 203 202 204 203 // insert/update 205 $this->add_index_row($mailbox, $sort_field, $sort_order, $data, $mbox_data, $exists); 204 $this->add_index_row($mailbox, $sort_field, $sort_order, $data, $mbox_data, 205 $exists, $index['modseq']); 206 206 } 207 207 … … 210 210 'sort_field' => $sort_field, 211 211 'sort_order' => $sort_order, 212 'modseq' => !empty($index['modseq']) ? $index['modseq'] : $mbox_data['HIGHESTMODSEQ'] 212 213 ); 213 214 … … 240 241 } 241 242 242 // Get index from DB 243 $index = $this->get_thread_row($mailbox); 244 $data = null; 243 // Get thread from DB (if DB wasn't already queried) 244 if (empty($this->icache[$mailbox]['thread_queried'])) { 245 $index = $this->get_thread_row($mailbox); 246 247 // set the flag that DB was already queried for thread 248 // this way we'll be able to skip one SELECT, when 249 // get_thread() is called more than once or after clear() 250 $this->icache[$mailbox]['thread_queried'] = true; 251 } 252 253 $data = null; 245 254 246 255 // Entry exist, check cache status … … 295 304 } 296 305 306 // @TODO: it would be nice if we could work with UIDs only 307 // then index would be not needed. For now we need it to 308 // map id to uid here and to update message id for cached message 309 297 310 // Convert IDs to UIDs 298 // @TODO: it would be nice if we could work with UIDs only 299 // then, e.g. when fetching search result, index would be not needed 311 $index = $this->get_index($mailbox, 'ANY'); 300 312 if (!$is_uid) { 301 $index = $this->get_index($mailbox, 'ANY');302 313 foreach ($msgs as $idx => $msgid) 303 314 if ($uid = $index[$msgid]) … … 305 316 } 306 317 307 $flag_fields = implode(', ', array_map(array($this->db, 'quoteIdentifier'), $this->flag_fields));308 309 318 // Fetch messages from cache 310 319 $sql_result = $this->db->query( 311 "SELECT uid, data, ".$flag_fields320 "SELECT uid, data, flags" 312 321 ." FROM ".get_table_name('cache_messages') 313 322 ." WHERE user_id = ?" … … 322 331 $uid = intval($sql_arr['uid']); 323 332 $result[$uid] = $this->build_message($sql_arr); 324 // save memory, we don't need a body here 333 334 // save memory, we don't need message body here (?) 325 335 $result[$uid]->body = null; 326 //@TODO: update message ID according to index data? 336 337 // update message ID according to index data 338 if (!empty($index) && ($id = array_search($uid, $index))) 339 $result[$uid]->id = $id; 327 340 328 341 if (!empty($result[$uid])) { … … 353 366 * @param string $mailbox Folder name 354 367 * @param int $uid Message UID 368 * @param bool $update If message doesn't exists in cache it will be fetched 369 * from IMAP server 370 * @param bool $no_cache Enables internal cache usage 355 371 * 356 372 * @return rcube_mail_header Message data 357 373 */ 358 function get_message($mailbox, $uid )374 function get_message($mailbox, $uid, $update = true, $cache = true) 359 375 { 360 376 // Check internal cache … … 365 381 } 366 382 367 $flag_fields = implode(', ', array_map(array($this->db, 'quoteIdentifier'), $this->flag_fields));368 369 383 $sql_result = $this->db->query( 370 "SELECT data, ".$flag_fields384 "SELECT flags, data" 371 385 ." FROM ".get_table_name('cache_messages') 372 386 ." WHERE user_id = ?" … … 379 393 $found = true; 380 394 381 //@TODO: update message ID according to index data? 395 // update message ID according to index data 396 $index = $this->get_index($mailbox, 'ANY'); 397 if (!empty($index) && ($id = array_search($uid, $index))) 398 $message->id = $id; 382 399 } 383 400 384 401 // Get the message from IMAP server 385 if (empty($message) ) {402 if (empty($message) && $update) { 386 403 $message = $this->imap->get_headers($uid, $mailbox, true); 387 404 // cache will be updated in close(), see below … … 394 411 // - set \Seen flag (UPDATE) 395 412 // This way we can skip one UPDATE 396 if (!empty($message) ) {413 if (!empty($message) && $cache) { 397 414 // Save current message from internal cache 398 415 $this->save_icache(); … … 422 439 return; 423 440 424 $msg = serialize($this->db->encode(clone $message)); 425 426 $flag_fields = array_map(array($this->db, 'quoteIdentifier'), $this->flag_fields); 427 $flag_values = array(); 428 429 foreach ($this->flag_fields as $flag) 430 $flag_values[] = (int) $message->$flag; 441 $msg = serialize($this->db->encode(clone $message)); 442 $flags = 0; 443 444 if (!empty($message->flags)) { 445 foreach ($this->flags as $idx => $flag) 446 if (!empty($message->flags[$flag])) 447 $flags += $idx; 448 } 449 unset($msg->flags); 431 450 432 451 // update cache record (even if it exists, the update 433 452 // here will work as select, assume row exist if affected_rows=0) 434 453 if (!$force) { 435 foreach ($flag_fields as $key => $val)436 $flag_data[] = $val . " = " . $flag_values[$key];437 438 454 $res = $this->db->query( 439 455 "UPDATE ".get_table_name('cache_messages') 440 ." SET data = ?, changed = ".$this->db->now() 441 .", " . implode(', ', $flag_data) 456 ." SET flags = ?, data = ?, changed = ".$this->db->now() 442 457 ." WHERE user_id = ?" 443 458 ." AND mailbox = ?" 444 459 ." AND uid = ?", 445 $ msg, $this->userid, $mailbox, (int) $message->uid);460 $flags, $msg, $this->userid, $mailbox, (int) $message->uid); 446 461 447 462 if ($this->db->affected_rows()) … … 452 467 $this->db->query( 453 468 "INSERT INTO ".get_table_name('cache_messages') 454 ." (user_id, mailbox, uid, changed, data, " . implode(', ', $flag_fields) . ")"455 ." VALUES (?, ?, ?, ".$this->db->now().", ?, " . implode(', ', $flag_values) . ")",456 $this->userid, $mailbox, (int) $message->uid, $ msg);469 ." (user_id, mailbox, uid, flags, changed, data)" 470 ." VALUES (?, ?, ?, ?, ".$this->db->now().", ?)", 471 $this->userid, $mailbox, (int) $message->uid, $flags, $msg); 457 472 } 458 473 … … 469 484 function change_flag($mailbox, $uids, $flag, $enabled = false) 470 485 { 471 $flag = strto lower($flag);472 473 if (in_array($flag, $this->flag_fields)) { 474 // Internal cache update475 if ($uids && count($uids) == 1 && ($uid = current($uids))476 && ($message = $this->icache['message'])477 && $message['mailbox'] == $mailbox && $message['object']->uid == $uid 478 ) {479 $message['object']->$flag = $enabled;480 return;481 }482 483 $ this->db->query(484 "UPDATE ".get_table_name('cache_messages')485 ." SET changed = ".$this->db->now()486 .", " .$this->db->quoteIdentifier($flag) . " = " . intval($enabled) 487 ." WHERE user_id = ?"488 ." AND mailbox = ?"489 .($uids !== null ? " AND uid IN (".$this->db->array2list((array)$uids, 'integer').")" : ""),490 $this->userid, $mailbox);491 }492 else {493 // @TODO: SELECT+UPDATE?494 $this->remove_message($mailbox, $uids);495 }486 $flag = strtoupper($flag); 487 $idx = (int) array_search($flag, $this->flags); 488 489 if (!$idx) { 490 return; 491 } 492 493 // Internal cache update 494 if ($uids && count($uids) == 1 && ($uid = current($uids)) 495 && ($message = $this->icache['message']) 496 && $message['mailbox'] == $mailbox && $message['object']->uid == $uid 497 ) { 498 $message['object']->flags[$flag] = $enabled; 499 return; 500 } 501 502 $this->db->query( 503 "UPDATE ".get_table_name('cache_messages') 504 ." SET changed = ".$this->db->now() 505 .", flags = flags ".($enabled ? "+ $idx" : "- $idx") 506 ." WHERE user_id = ?" 507 ." AND mailbox = ?" 508 .($uids !== null ? " AND uid IN (".$this->db->array2list((array)$uids, 'integer').")" : "") 509 ." AND (flags & $idx) ".($enabled ? "= 0" : "= $idx"), 510 $this->userid, $mailbox); 496 511 } 497 512 … … 534 549 * 535 550 * @param string $mailbox Folder name 536 */ 537 function remove_index($mailbox = null) 538 { 539 $this->db->query( 540 "DELETE FROM ".get_table_name('cache_index') 541 ." WHERE user_id = ".intval($this->userid) 542 .(strlen($mailbox) ? " AND mailbox = ".$this->db->quote($mailbox) : "") 543 ); 544 545 if (strlen($mailbox)) 551 * @param bool $remove Enable to remove the DB row 552 */ 553 function remove_index($mailbox = null, $remove = false) 554 { 555 // The index should be only removed from database when 556 // UIDVALIDITY was detected or the mailbox is empty 557 // otherwise use 'valid' flag to not loose HIGHESTMODSEQ value 558 if ($remove) 559 $this->db->query( 560 "DELETE FROM ".get_table_name('cache_index') 561 ." WHERE user_id = ".intval($this->userid) 562 .(strlen($mailbox) ? " AND mailbox = ".$this->db->quote($mailbox) : "") 563 ); 564 else 565 $this->db->query( 566 "UPDATE ".get_table_name('cache_index') 567 ." SET valid = 0" 568 ." WHERE user_id = ".intval($this->userid) 569 .(strlen($mailbox) ? " AND mailbox = ".$this->db->quote($mailbox) : "") 570 ); 571 572 if (strlen($mailbox)) { 546 573 unset($this->icache[$mailbox]['index']); 574 // Index removed, set flag to skip SELECT query in get_index() 575 $this->icache[$mailbox]['index_queried'] = true; 576 } 547 577 else 548 578 $this->icache = array(); … … 563 593 ); 564 594 565 if (strlen($mailbox)) 595 if (strlen($mailbox)) { 566 596 unset($this->icache[$mailbox]['thread']); 597 // Thread data removed, set flag to skip SELECT query in get_thread() 598 $this->icache[$mailbox]['thread_queried'] = true; 599 } 567 600 else 568 601 $this->icache = array(); … … 578 611 function clear($mailbox = null, $uids = null) 579 612 { 580 $this->remove_index($mailbox );613 $this->remove_index($mailbox, true); 581 614 $this->remove_thread($mailbox); 582 615 $this->remove_message($mailbox, $uids); … … 619 652 } 620 653 621 622 654 /** 623 655 * Fetches index data from database … … 627 659 // Get index from DB 628 660 $sql_result = $this->db->query( 629 "SELECT data "661 "SELECT data, valid" 630 662 ." FROM ".get_table_name('cache_index') 631 663 ." WHERE user_id = ?" … … 637 669 638 670 return array( 671 'valid' => $sql_arr['valid'], 639 672 'seq' => explode(',', $data[0]), 640 673 'uid' => explode(',', $data[1]), … … 644 677 'validity' => $data[5], 645 678 'uidnext' => $data[6], 679 'modseq' => $data[7], 646 680 ); 647 681 } … … 667 701 $data = explode('@', $sql_arr['data']); 668 702 703 // Uncompress data, see add_thread_row() 704 // $data[0] = str_replace(array('*', '^', '#'), array(';a:0:{}', 'i:', ';a:1:'), $data[0]); 669 705 $data[0] = unserialize($data[0]); 706 670 707 // build 'depth' and 'children' arrays 671 708 $depth = $children = array(); … … 690 727 */ 691 728 private function add_index_row($mailbox, $sort_field, $sort_order, 692 $data = array(), $mbox_data = array(), $exists = false )729 $data = array(), $mbox_data = array(), $exists = false, $modseq = null) 693 730 { 694 731 $data = array( … … 700 737 (int) $mbox_data['UIDVALIDITY'], 701 738 (int) $mbox_data['UIDNEXT'], 739 $modseq ? $modseq : $mbox_data['HIGHESTMODSEQ'], 702 740 ); 703 741 $data = implode('@', $data); … … 706 744 $sql_result = $this->db->query( 707 745 "UPDATE ".get_table_name('cache_index') 708 ." SET data = ?, changed = ".$this->db->now()746 ." SET data = ?, valid = 1, changed = ".$this->db->now() 709 747 ." WHERE user_id = ?" 710 748 ." AND mailbox = ?", … … 713 751 $sql_result = $this->db->query( 714 752 "INSERT INTO ".get_table_name('cache_index') 715 ." (user_id, mailbox, data, changed)"716 ." VALUES (?, ?, ?, ".$this->db->now().")",753 ." (user_id, mailbox, data, valid, changed)" 754 ." VALUES (?, ?, ?, 1, ".$this->db->now().")", 717 755 $this->userid, $mailbox, $data); 718 756 } … … 724 762 private function add_thread_row($mailbox, $data = array(), $mbox_data = array(), $exists = false) 725 763 { 764 $tree = serialize($data['tree']); 765 // This significantly reduces data length 766 // $tree = str_replace(array(';a:0:{}', 'i:', ';a:1:'), array('*', '^', '#'), $tree); 767 726 768 $data = array( 727 serialize($data['tree']),769 $tree, 728 770 (int) $this->skip_deleted, 729 771 (int) $mbox_data['UIDVALIDITY'], … … 765 807 766 808 // Check UIDVALIDITY 767 // @TODO: while we're storing message sequence numbers in thread768 // index, should UIDVALIDITY invalidate the thread data?769 809 if ($index['validity'] != $mbox_data['UIDVALIDITY']) { 770 // the whole cache (all folders) is invalid 771 $this->clear(); 810 $this->clear($mailbox); 772 811 $exists = false; 773 812 return false; … … 781 820 } 782 821 822 // Validation flag 823 if (!$is_thread && empty($index['valid'])) { 824 unset($this->icache[$mailbox][$is_thread ? 'thread' : 'index']); 825 return false; 826 } 827 828 // Index was created with different skip_deleted setting 829 if ($this->skip_deleted != $index['deleted']) { 830 return false; 831 } 832 833 // Check HIGHESTMODSEQ 834 if (!empty($index['modseq']) && !empty($mbox_data['HIGHESTMODSEQ']) 835 && $index['modseq'] == $mbox_data['HIGHESTMODSEQ'] 836 ) { 837 return true; 838 } 839 783 840 // Check UIDNEXT 784 841 if ($index['uidnext'] != $mbox_data['UIDNEXT']) { 785 842 unset($this->icache[$mailbox][$is_thread ? 'thread' : 'index']); 786 return false;787 }788 789 // Index was created with different skip_deleted setting790 if ($this->skip_deleted != $index['deleted']) {791 843 return false; 792 844 } … … 849 901 850 902 /** 903 * Synchronizes the mailbox. 904 * 905 * @param string $mailbox Folder name 906 */ 907 function synchronize($mailbox) 908 { 909 // RFC4549: Synchronization Operations for Disconnected IMAP4 Clients 910 // RFC4551: IMAP Extension for Conditional STORE Operation 911 // or Quick Flag Changes Resynchronization 912 // RFC5162: IMAP Extensions for Quick Mailbox Resynchronization 913 914 // @TODO: synchronize with other methods? 915 $qresync = $this->imap->get_capability('QRESYNC'); 916 $condstore = $qresync ? true : $this->imap->get_capability('CONDSTORE'); 917 918 if (!$qresync && !$condstore) { 919 return; 920 } 921 922 // Get stored index 923 $index = $this->get_index_row($mailbox); 924 925 // database is empty 926 if (empty($index)) { 927 // set the flag that DB was already queried for index 928 // this way we'll be able to skip one SELECT in get_index() 929 $this->icache[$mailbox]['index_queried'] = true; 930 return; 931 } 932 933 $this->icache[$mailbox]['index'] = $index; 934 935 // no last HIGHESTMODSEQ value 936 if (empty($index['modseq'])) { 937 return; 938 } 939 940 // NOTE: make sure the mailbox isn't selected, before 941 // enabling QRESYNC and invoking SELECT 942 if ($this->imap->conn->selected !== null) { 943 $this->imap->conn->close(); 944 } 945 946 // Enable QRESYNC 947 $res = $this->imap->conn->enable($qresync ? 'QRESYNC' : 'CONDSTORE'); 948 if (!is_array($res)) { 949 return; 950 } 951 952 // Get mailbox data (UIDVALIDITY, HIGHESTMODSEQ, counters, etc.) 953 $mbox_data = $this->imap->mailbox_data($mailbox); 954 955 if (empty($mbox_data)) { 956 return; 957 } 958 959 // Check UIDVALIDITY 960 if ($index['validity'] != $mbox_data['UIDVALIDITY']) { 961 $this->clear($mailbox); 962 return; 963 } 964 965 // QRESYNC not supported on specified mailbox 966 if (!empty($mbox_data['NOMODSEQ']) || empty($mbox_data['HIGHESTMODSEQ'])) { 967 return; 968 } 969 970 // Nothing new 971 if ($mbox_data['HIGHESTMODSEQ'] == $index['modseq']) { 972 return; 973 } 974 975 // Get known uids 976 $uids = array(); 977 $sql_result = $this->db->query( 978 "SELECT uid" 979 ." FROM ".get_table_name('cache_messages') 980 ." WHERE user_id = ?" 981 ." AND mailbox = ?", 982 $this->userid, $mailbox); 983 984 while ($sql_arr = $this->db->fetch_assoc($sql_result)) { 985 $uids[] = $sql_arr['uid']; 986 } 987 988 // No messages in database, nothing to sync 989 if (empty($uids)) { 990 return; 991 } 992 993 // Get modified flags and vanished messages 994 // UID FETCH 1:* (FLAGS) (CHANGEDSINCE 0123456789 VANISHED) 995 $result = $this->imap->conn->fetch($mailbox, 996 !empty($uids) ? $uids : '1:*', true, array('FLAGS'), 997 $index['modseq'], $qresync); 998 999 if (!empty($result)) { 1000 foreach ($result as $id => $msg) { 1001 $uid = $msg->uid; 1002 // Remove deleted message 1003 if ($this->skip_deleted && !empty($msg->flags['DELETED'])) { 1004 $this->remove_message($mailbox, $uid); 1005 continue; 1006 } 1007 1008 $flags = 0; 1009 if (!empty($msg->flags)) { 1010 foreach ($this->flags as $idx => $flag) 1011 if (!empty($msg->flags[$flag])) 1012 $flags += $idx; 1013 } 1014 1015 $this->db->query( 1016 "UPDATE ".get_table_name('cache_messages') 1017 ." SET flags = ?, changed = ".$this->db->now() 1018 ." WHERE user_id = ?" 1019 ." AND mailbox = ?" 1020 ." AND uid = ?" 1021 ." AND flags <> ?", 1022 $flags, $this->userid, $mailbox, $uid, $flags); 1023 } 1024 } 1025 1026 // Get VANISHED 1027 if ($qresync) { 1028 $mbox_data = $this->imap->mailbox_data($mailbox); 1029 1030 // Removed messages 1031 if (!empty($mbox_data['VANISHED'])) { 1032 $uids = rcube_imap_generic::uncompressMessageSet($mbox_data['VANISHED']); 1033 if (!empty($uids)) { 1034 // remove messages from database 1035 $this->remove_message($mailbox, $uids); 1036 1037 // Invalidate thread indexes (?) 1038 $this->remove_thread($mailbox); 1039 } 1040 } 1041 } 1042 1043 $sort_field = $index['sort_field']; 1044 $sort_order = $index['sort_order']; 1045 $exists = true; 1046 1047 // Validate index 1048 if (!$this->validate($mailbox, $index, $exists)) { 1049 // Update index 1050 $data = $this->get_index_data($mailbox, $sort_field, $sort_order, $mbox_data); 1051 } 1052 else { 1053 $data = array_combine($index['seq'], $index['uid']); 1054 } 1055 1056 // update index and/or HIGHESTMODSEQ value 1057 $this->add_index_row($mailbox, $sort_field, $sort_order, $data, $mbox_data, $exists); 1058 1059 // update internal cache for get_index() 1060 $this->icache[$mailbox]['index']['result'] = $data; 1061 } 1062 1063 1064 /** 851 1065 * Converts cache row into message object. 852 1066 * … … 860 1074 861 1075 if ($message) { 862 foreach ($this->flag_fields as $field) 863 $message->$field = (bool) $sql_arr[$field]; 1076 $message->flags = array(); 1077 foreach ($this->flags as $idx => $flag) 1078 if (($sql_arr['flags'] & $idx) == $idx) 1079 $message->flags[$flag] = true; 864 1080 } 865 1081 … … 907 1123 * Prepares message object to be stored in database. 908 1124 */ 909 private function message_object_prepare($msg , $recursive = false)910 { 911 // Remove body too big (> 500kB)912 if ($ recursive || ($msg->body && strlen($msg->body) > 500 * 1024)) {1125 private function message_object_prepare($msg) 1126 { 1127 // Remove body too big (>25kB) 1128 if ($msg->body && strlen($msg->body) > 25 * 1024) { 913 1129 unset($msg->body); 914 1130 } … … 923 1139 if (is_array($msg->structure->parts)) { 924 1140 foreach ($msg->structure->parts as $idx => $part) { 925 $msg->structure->parts[$idx] = $this->message_object_prepare($part , true);1141 $msg->structure->parts[$idx] = $this->message_object_prepare($part); 926 1142 } 927 1143 } … … 929 1145 return $msg; 930 1146 } 1147 1148 1149 /** 1150 * Fetches index data from IMAP server 1151 */ 1152 private function get_index_data($mailbox, $sort_field, $sort_order, $mbox_data = array()) 1153 { 1154 $data = array(); 1155 1156 if (empty($mbox_data)) { 1157 $mbox_data = $this->imap->mailbox_data($mailbox); 1158 } 1159 1160 // Prevent infinite loop. 1161 // It happens when rcube_imap::message_index_direct() is called. 1162 // There id2uid() is called which will again call get_index() and so on. 1163 if (!$sort_field && !$this->skip_deleted) 1164 $this->icache['pending_index_update'] = true; 1165 1166 if ($mbox_data['EXISTS']) { 1167 // fetch sorted sequence numbers 1168 $data_seq = $this->imap->message_index_direct($mailbox, $sort_field, $sort_order); 1169 // fetch UIDs 1170 if (!empty($data_seq)) { 1171 // Seek in internal cache 1172 if (array_key_exists('index', (array)$this->icache[$mailbox]) 1173 && array_key_exists('result', (array)$this->icache[$mailbox]['index']) 1174 ) 1175 $data_uid = $this->icache[$mailbox]['index']['result']; 1176 else 1177 $data_uid = $this->imap->conn->fetchUIDs($mailbox, $data_seq); 1178 1179 // build index 1180 if (!empty($data_uid)) { 1181 foreach ($data_seq as $seq) 1182 if ($uid = $data_uid[$seq]) 1183 $data[$seq] = $uid; 1184 } 1185 } 1186 } 1187 1188 // Reset internal flags 1189 $this->icache['pending_index_update'] = false; 1190 1191 return $data; 1192 } 931 1193 } -
trunk/roundcubemail/program/include/rcube_imap_generic.php
r5204 r5233 7 7 | This file is part of the Roundcube Webmail client | 8 8 | Copyright (C) 2005-2010, The Roundcube Dev Team | 9 | Copyright (C) 2011, Kolab Systems AG | 9 10 | Licensed under the GNU GPL | 10 11 | | … … 55 56 public $priority; 56 57 public $mdn_to; 57 58 public $flags;59 public $mdnsent = false;60 public $seen = false;61 public $deleted = false;62 public $answered = false;63 public $forwarded = false;64 public $flagged = false;65 58 public $others = array(); 59 public $flags = array(); 66 60 } 67 61 … … 690 684 $this->error = ''; 691 685 $this->errornum = self::ERROR_OK; 692 $this->selected = '';686 $this->selected = null; 693 687 $this->user = $user; 694 688 $this->host = $host; … … 887 881 } 888 882 889 if ($this->selected == $mailbox) {883 if ($this->selected === $mailbox) { 890 884 return true; 891 885 } … … 1050 1044 1051 1045 if ($result == self::ERROR_OK) { 1052 $this->selected = ''; // state has changed, need to reselect1046 $this->selected = null; // state has changed, need to reselect 1053 1047 return true; 1054 1048 } … … 1068 1062 1069 1063 if ($result == self::ERROR_OK) { 1070 $this->selected = '';1064 $this->selected = null; 1071 1065 return true; 1072 1066 } … … 1135 1129 1136 1130 if ($res) { 1137 if ($this->selected == $mailbox)1131 if ($this->selected === $mailbox) 1138 1132 $res = $this->close(); 1139 1133 else … … 1154 1148 { 1155 1149 if ($refresh) { 1156 $this->selected = '';1157 } 1158 1159 if ($this->selected == $mailbox) {1150 $this->selected = null; 1151 } 1152 1153 if ($this->selected === $mailbox) { 1160 1154 return $this->data['EXISTS']; 1161 1155 } … … 1191 1185 $this->select($mailbox); 1192 1186 1193 if ($this->selected == $mailbox) {1187 if ($this->selected === $mailbox) { 1194 1188 return $this->data['RECENT']; 1195 1189 } … … 1677 1671 if (!empty($value)) { 1678 1672 foreach ((array)$value as $flag) { 1679 $flag = str_replace('\\', '', $flag); 1680 1681 switch (strtoupper($flag)) { 1682 case 'SEEN': 1683 $result[$id]->seen = true; 1684 break; 1685 case 'DELETED': 1686 $result[$id]->deleted = true; 1687 break; 1688 case 'ANSWERED': 1689 $result[$id]->answered = true; 1690 break; 1691 case '$FORWARDED': 1692 $result[$id]->forwarded = true; 1693 break; 1694 case '$MDNSENT': 1695 $result[$id]->mdnsent = true; 1696 break; 1697 case 'FLAGGED': 1698 $result[$id]->flagged = true; 1699 break; 1700 default: 1701 $result[$id]->flags[] = $flag; 1702 break; 1703 } 1673 $flag = str_replace(array('$', '\\'), '', $flag); 1674 $flag = strtoupper($flag); 1675 1676 $result[$id]->flags[$flag] = true; 1704 1677 } 1705 1678 } … … 1813 1786 // Sample: * VANISHED (EARLIER) 300:310,405,411 1814 1787 1815 else if (preg_match('/^\* VANISHED [ EARLIER]*/i', $line, $match)) {1788 else if (preg_match('/^\* VANISHED [()EARLIER]*/i', $line, $match)) { 1816 1789 $line = substr($line, strlen($match[0])); 1817 1790 $v_data = $this->tokenizeResponse($line, 1); -
trunk/roundcubemail/program/js/app.js
r5221 r5233 1648 1648 $.extend(this.env.messages[uid], { 1649 1649 deleted: flags.deleted?1:0, 1650 replied: flags. replied?1:0,1651 unread: flags.unread?1:0,1650 replied: flags.answered?1:0, 1651 unread: !flags.seen?1:0, 1652 1652 forwarded: flags.forwarded?1:0, 1653 1653 flagged: flags.flagged?1:0, … … 1672 1672 css_class = 'message' 1673 1673 + (even ? ' even' : ' odd') 1674 + ( flags.unread? ' unread' : '')1674 + (!flags.seen ? ' unread' : '') 1675 1675 + (flags.deleted ? ' deleted' : '') 1676 1676 + (flags.flagged ? ' flagged' : '') 1677 + (flags.unread_children && !flags.unread&& !this.env.autoexpand_threads ? ' unroot' : '')1677 + (flags.unread_children && flags.seen && !this.env.autoexpand_threads ? ' unroot' : '') 1678 1678 + (message.selected ? ' selected' : ''), 1679 1679 // for performance use DOM instead of jQuery here … … 1690 1690 if (flags.deleted) 1691 1691 css_class += ' deleted'; 1692 else if ( flags.unread)1692 else if (!flags.seen) 1693 1693 css_class += ' unread'; 1694 1694 else if (flags.unread_children > 0) 1695 1695 css_class += ' unreadchildren'; 1696 1696 } 1697 if (flags. replied)1697 if (flags.answered) 1698 1698 css_class += ' replied'; 1699 1699 if (flags.forwarded) … … 1763 1763 if (flags.deleted) 1764 1764 css_class = 'deleted'; 1765 else if ( flags.unread)1765 else if (!flags.seen) 1766 1766 css_class = 'unread'; 1767 1767 else if (flags.unread_children > 0) … … 2057 2057 2058 2058 while (new_row) { 2059 if (new_row.nodeType == 1 && (r = this.message_list.rows[new_row.uid]) 2060 && r.unread_children) { 2059 if (new_row.nodeType == 1 && (r = this.message_list.rows[new_row.uid]) && r.unread_children) { 2061 2060 this.message_list.expand_all(r); 2062 2061 this.set_unread_children(r.uid); … … 3543 3542 this.insert_recipient = function(id) 3544 3543 { 3545 if ( !this.env.contacts[id] || !this.ksearch_input)3544 if (id === null || !this.env.contacts[id] || !this.ksearch_input) 3546 3545 return; 3547 3546 -
trunk/roundcubemail/program/steps/mail/check_recent.inc
r5228 r5233 35 35 // check recent/unseen counts 36 36 foreach ($a_mailboxes as $mbox_name) { 37 $is_current = $mbox_name == $current; 38 if ($is_current) { 39 // Synchronize mailbox cache, handle flag changes 40 $IMAP->mailbox_sync($mbox_name); 41 } 42 43 // Get mailbox status 37 44 $status = $IMAP->mailbox_status($mbox_name); 38 45 39 46 if ($status & 1) { 40 47 // trigger plugin hook 41 $RCMAIL->plugins->exec_hook('new_messages', array('mailbox' => $mbox_name)); 48 $RCMAIL->plugins->exec_hook('new_messages', 49 array('mailbox' => $mbox_name, 'is_current' => $is_current)); 42 50 } 43 51 44 52 rcmail_send_unread_count($mbox_name, true); 45 53 46 if ($status && $ mbox_name == $current) {54 if ($status && $is_current) { 47 55 // refresh saved search set 48 56 $search_request = get_input_value('_search', RCUBE_INPUT_GPC); -
trunk/roundcubemail/program/steps/mail/compose.inc
r5226 r5233 157 157 $CONFIG['prefer_html'] = $CONFIG['prefer_html'] || $CONFIG['htmleditor'] || $compose_mode == RCUBE_COMPOSE_DRAFT || $compose_mode == RCUBE_COMPOSE_EDIT; 158 158 $MESSAGE = new rcube_message($msg_uid); 159 159 160 160 // make sure message is marked as read 161 if ($MESSAGE && $MESSAGE->headers && !$MESSAGE->headers->seen)161 if ($MESSAGE && $MESSAGE->headers && empty($MESSAGE->headers->flags['SEEN'])) 162 162 $IMAP->set_flag($msg_uid, 'SEEN'); 163 163 164 164 if (!empty($MESSAGE->headers->charset)) 165 165 $IMAP->set_charset($MESSAGE->headers->charset); 166 166 167 167 if ($compose_mode == RCUBE_COMPOSE_REPLY) 168 168 { -
trunk/roundcubemail/program/steps/mail/func.inc
r5226 r5233 288 288 } 289 289 290 $a_msg_flags = array_change_key_case(array_map('intval', (array) $header->flags)); 290 291 if ($header->depth) 291 292 $a_msg_flags['depth'] = $header->depth; … … 298 299 if ($header->unread_children) 299 300 $a_msg_flags['unread_children'] = $header->unread_children; 300 if ($header->deleted)301 $a_msg_flags['deleted'] = 1;302 if (!$header->seen)303 $a_msg_flags['unread'] = 1;304 if ($header->answered)305 $a_msg_flags['replied'] = 1;306 if ($header->forwarded)307 $a_msg_flags['forwarded'] = 1;308 if ($header->flagged)309 $a_msg_flags['flagged'] = 1;310 301 if ($header->others['list-post']) 311 302 $a_msg_flags['ml'] = 1; … … 316 307 $a_msg_flags['mbox'] = $mbox; 317 308 318 // merge with plugin result 309 // merge with plugin result (Deprecated, use $header->flags) 319 310 if (!empty($header->list_flags) && is_array($header->list_flags)) 320 311 $a_msg_flags = array_merge($a_msg_flags, $header->list_flags); … … 1455 1446 $message = new rcube_message($message); 1456 1447 1457 if ($message->headers->mdn_to && !$message->headers->mdnsent&&1448 if ($message->headers->mdn_to && empty($message->headers->flags['MDNSENT']) && 1458 1449 ($IMAP->check_permflag('MDNSENT') || $IMAP->check_permflag('*'))) 1459 1450 { -
trunk/roundcubemail/program/steps/mail/list.inc
r4410 r5233 53 53 54 54 $mbox_name = $IMAP->get_mailbox_name(); 55 56 // Synchronize mailbox cache, handle flag changes 57 $IMAP->mailbox_sync($mbox_name); 55 58 56 59 // initialize searching result if search_filter is used … … 117 120 // send response 118 121 $OUTPUT->send(); 119 120 -
trunk/roundcubemail/program/steps/mail/move_del.inc
r4410 r5233 117 117 } 118 118 119 if ($RCMAIL->action =='moveto' && strlen($target)) {119 if ($RCMAIL->action == 'moveto' && strlen($target)) { 120 120 rcmail_send_unread_count($target, true); 121 121 } -
trunk/roundcubemail/program/steps/mail/show.inc
r5190 r5233 77 77 78 78 // check for unset disposition notification 79 if ($MESSAGE->headers->mdn_to && 80 !$MESSAGE->headers->mdnsent && !$MESSAGE->headers->seen && 81 ($IMAP->check_permflag('MDNSENT') || $IMAP->check_permflag('*')) && 82 $mbox_name != $CONFIG['drafts_mbox'] && 83 $mbox_name != $CONFIG['sent_mbox']) 84 { 79 if ($MESSAGE->headers->mdn_to 80 && empty($MESSAGE->headers->flags['MDNSENT']) 81 && empty($MESSAGE->headers->flags['SEEN']) 82 && ($IMAP->check_permflag('MDNSENT') || $IMAP->check_permflag('*')) 83 && $mbox_name != $CONFIG['drafts_mbox'] 84 && $mbox_name != $CONFIG['sent_mbox'] 85 ) { 85 86 $mdn_cfg = intval($CONFIG['mdn_requests']); 86 87 … … 101 102 } 102 103 103 if (!$MESSAGE->headers->seen && ($RCMAIL->action == 'show' || ($RCMAIL->action == 'preview' && intval($CONFIG['preview_pane_mark_read']) == 0))) 104 if (empty($MESSAGE->headers->flags['SEEN']) 105 && ($RCMAIL->action == 'show' || ($RCMAIL->action == 'preview' && intval($CONFIG['preview_pane_mark_read']) == 0)) 106 ) { 104 107 $RCMAIL->plugins->exec_hook('message_read', array('uid' => $MESSAGE->uid, 105 108 'mailbox' => $mbox_name, 'message' => $MESSAGE)); 109 } 106 110 } 107 111 … … 200 204 201 205 // mark message as read 202 if ($MESSAGE && $MESSAGE->headers && !$MESSAGE->headers->seen&&206 if ($MESSAGE && $MESSAGE->headers && empty($MESSAGE->headers->flags['SEEN']) && 203 207 ($RCMAIL->action == 'show' || ($RCMAIL->action == 'preview' && intval($CONFIG['preview_pane_mark_read']) == 0))) 204 208 {
Note: See TracChangeset
for help on using the changeset viewer.
