From 5fe00abb2cdde93a178812d19178d8d8d07bbaff Mon Sep 17 00:00:00 2001 From: Michael M Slusarz Date: Wed, 15 Dec 2010 16:30:53 -0700 Subject: [PATCH] Rewrite IMAP flags handling/display code Rewrite to match recent search rewrite. Biggest benefit: removes a large amount of logic from the preferences file (and, thus, wasted storage in the session). Move all flags to separate objects, and use these objects to interact with the various flag quirks. This commit does make a fairly significant UI change: you no longer mark a message as 'Unseen', you unmark it as 'Seen'. Not quite as intuitive to me, but this is the way the IMAP specs define it and the way that other MUAs (e.g. Thunderbird) show to user. But at the internal level it allows us to get rid of the 'inverse' flagging. Fix bug: Allow filtering of ALL IMAP flags in dimp, not just user settable ones. fullmessage-dimp.js -> message-dimp.js For those upgrading that have custom flags you don't want to lose, this script is what I used to convert. YMMV. 'none')); $registry->setAuth(***USERNAME***, array()); $msgflags = array_merge( json_decode($prefs->getValue('msgflags_user'), true), json_decode($prefs->getValue('msgflags'), true) ); $out = array(); foreach ($msgflags as $key => $val) { if ($val['t'] == 'imapp') { $out[] = new IMP_Flag_User($val['l'], $key, $val['b']); } } $prefs->setValue('msgflags', serialize($out)); $prefs->remove('msgflags_user'); --- imp/config/prefs.php.dist | 146 +------ imp/js/compose-dimp.js | 6 +- imp/js/dimpbase.js | 185 ++++----- imp/js/dimpcore.js | 2 +- imp/js/{fullmessage-dimp.js => message-dimp.js} | 22 +- imp/lib/Ajax/Application.php | 202 ++++++---- imp/lib/Api.php | 15 +- imp/lib/Application.php | 1 + imp/lib/Flag/Base.php | 229 +++++++++++ imp/lib/Flag/Imap.php | 50 +++ imp/lib/Flag/Imap/Answered.php | 36 ++ imp/lib/Flag/Imap/Deleted.php | 40 ++ imp/lib/Flag/Imap/Draft.php | 40 ++ imp/lib/Flag/Imap/Flagged.php | 40 ++ imp/lib/Flag/Imap/Forwarded.php | 36 ++ imp/lib/Flag/Imap/Seen.php | 37 ++ imp/lib/Flag/System.php | 17 + imp/lib/Flag/System/Attachment.php | 46 +++ imp/lib/Flag/System/Encrypted.php | 43 +++ imp/lib/Flag/System/HighPriority.php | 48 +++ imp/lib/Flag/System/LowPriority.php | 40 ++ imp/lib/Flag/System/Personal.php | 54 +++ imp/lib/Flag/System/Signed.php | 40 ++ imp/lib/Flag/System/Unseen.php | 63 +++ imp/lib/Flag/User.php | 102 +++++ imp/lib/Flags.php | 397 +++++++++++++++++++ imp/lib/Imap/Flags.php | 484 ------------------------ imp/lib/Indices.php | 38 +- imp/lib/Injector/Factory/Flags.php | 66 ++++ imp/lib/Message.php | 6 +- imp/lib/Prefs/Ui.php | 69 ++-- imp/lib/Search/Element/Flag.php | 3 +- imp/lib/Ui/Mailbox.php | 32 -- imp/lib/Views/ListMessages.php | 14 +- imp/lib/Views/ShowMessage.php | 22 +- imp/mailbox-mimp.php | 14 +- imp/mailbox.php | 41 +- imp/message-dimp.php | 13 +- imp/message-mimp.php | 14 +- imp/message.php | 31 +- imp/package.xml | 4 +- imp/search-basic.php | 13 +- imp/search.php | 15 +- imp/templates/dimp/index.inc | 3 + imp/templates/dimp/javascript_defs.php | 24 +- imp/templates/mobile/javascript_defs.php | 22 +- imp/templates/prefs/flags.html | 28 +- imp/themes/default/dimp/screen.css | 2 +- imp/themes/default/screen.css | 3 + imp/themes/silver/screen.css | 3 + 50 files changed, 1861 insertions(+), 1040 deletions(-) rename imp/js/{fullmessage-dimp.js => message-dimp.js} (91%) create mode 100644 imp/lib/Flag/Base.php create mode 100644 imp/lib/Flag/Imap.php create mode 100644 imp/lib/Flag/Imap/Answered.php create mode 100644 imp/lib/Flag/Imap/Deleted.php create mode 100644 imp/lib/Flag/Imap/Draft.php create mode 100644 imp/lib/Flag/Imap/Flagged.php create mode 100644 imp/lib/Flag/Imap/Forwarded.php create mode 100644 imp/lib/Flag/Imap/Seen.php create mode 100644 imp/lib/Flag/System.php create mode 100644 imp/lib/Flag/System/Attachment.php create mode 100644 imp/lib/Flag/System/Encrypted.php create mode 100644 imp/lib/Flag/System/HighPriority.php create mode 100644 imp/lib/Flag/System/LowPriority.php create mode 100644 imp/lib/Flag/System/Personal.php create mode 100644 imp/lib/Flag/System/Signed.php create mode 100644 imp/lib/Flag/System/Unseen.php create mode 100644 imp/lib/Flag/User.php create mode 100644 imp/lib/Flags.php delete mode 100644 imp/lib/Imap/Flags.php create mode 100644 imp/lib/Injector/Factory/Flags.php diff --git a/imp/config/prefs.php.dist b/imp/config/prefs.php.dist index 7088be3a4..24e780f15 100644 --- a/imp/config/prefs.php.dist +++ b/imp/config/prefs.php.dist @@ -987,149 +987,11 @@ $_prefs['flagmanagement'] = array( 'type' => 'special' ); -// Message flags - system defaults -// This entry should normally never be changed. It provides the base flags -// for all users. Flags specific to a certain user should be defined in -// 'msgflags_user'. -$_prefs['msgflags'] = array( - // Format: - // KEY: Flag name - // VALUE: Array with the following entries - // 'a' - (string) [abbreviation] The abbreviation used in - // the mobile (mimp) view. - // DEFAULT: Don't show flag - // 'b' - (string) [background] The CSS background color - // DEFAULT: Use value of 'msgflags_color' - // 'c' - (string) [class] The CSS background class (used to - // display status icon). - // NO DEFAULT (entry required) - // 'd' - (boolean) [delete] If true, entry can be deleted. - // DEFAULT: false - // 'l' - (string) [label] The flag text label. - // NO DEFAULT (entry required) - // 't' - (string) [type] The flag type: - // 'atc' - Attachment information - // 'imap' - IMAP system flags (not settable by user) - // 'imapp' - IMAP flags (personal flags - created by user - // through the prefs interface) - // 'imapu' - IMAP system flags (settable by user) - // 'imp' - IMP defined flags - // NO DEFAULT (entry required) - 'value' => json_encode(array( - // Static internal imp flags (i.e. status icons) - // THESE ENTRIES MUST NOT BE DELETED - 'personal' => array( - 'a' => '+', - 'c' => 'flagPersonal', - 'l' => _("Personal"), - 't' => 'imp' - ), - 'highpri' => array( - 'a' => '!', - 'b' => '#fcc', - 'c' => 'flagHighpriority', - 'l' => _("High Priority"), - 't' => 'imp' - ), - 'lowpri' => array( - 'a' => '0', - 'c' => 'flagLowpriority', - 'l' => _("Low Priority"), - 't' => 'imp' - ), - - // Attachment flags - // THESE ENTRIES MUST NOT BE DELETED - 'signed' => array( - 'c' => 'flagSignedmsg', - 'l' => _("Message is Signed"), - 't' => 'atc' - ), - 'encrypt' => array( - 'c' => 'flagEncryptmsg', - 'l' => _("Message is Encrypted"), - 't' => 'atc' - ), - 'attach' => array( - 'c' => 'flagAttachmsg', - 'l' => _("Message has Attachments"), - 't' => 'atc' - ), - - // IMAP flags - // KEY: IMAP flag as it exists on the IMAP server - // VALUES (additional to base values): - // 'n' - (boolean) [NOT match] Don't match the flag. - // DEFAULT: false - - // System IMAP flags (RFC 3501 [2.3.2]) - '\\answered' => array( - 'a' => 'r', - 'b' => '#cfc', - 'c' => 'flagAnswered', - 'l' => _("Answered"), - // By default, this flag is not settable by the user - it is - // automatically set when a message is replied to. - 't' => 'imap' - ), - '\\draft' => array( - 'a' => 'd', - 'c' => 'flagDraft', - 'l' => _("Draft"), - // By default, this flag is not settable by the user - it is - // automatically set/reset when a message is drafted/finished. - 't' => 'imap' - ), - '\\deleted' => array( - 'a' => 'D', - 'b' => '#999', - 'c' => 'flagDeleted', - 'l' => _("Deleted"), - // By default, this flag is not settable by the user - it is - // handled via the Delete/Undelete links. - 't' => 'imap' - ), - '\\seen' => array( - 'a' => 'N', - 'b' => '#eef', - 'c' => 'flagUnseen', - 'l' => _("Unseen"), - 'n' => true, - 't' => 'imapu' - ), - '\\flagged' => array( - 'a' => '*', - 'b' => '#fcc', - 'c' => 'flagFlagged', - 'l' => _("Flagged for Followup"), - 't' => 'imapu' - ), - - // Forwarded flag (RFC 5550 [5.9]) - '$forwarded' => array( - 'a' => 'F', - 'b' => '#bfdfdf', - 'c' => 'flagForwarded', - 'l' => _("Forwarded"), - // Pursuant to RFC, this flag SHOULD NOT be changed by the user - 't' => 'imap' - ), - )) -); - -// Message flags - user specific // This array contains the list of flags created by the user through the -// flags UI. Additionally, an admin can define default non-system flags -// for a user in this preference. -// See the 'msgflags' preference for the format of this value. -$_prefs['msgflags_user'] = array( - // 'value' = json_encode(array()) - 'value' => '[]' -); - -// The default color to use for flags that don't require row highlighting. -$_prefs['msgflags_color'] = array( - 'value' => '#ddd' +// flags UI, and any modifications to the built-in system flags. +$_prefs['msgflags'] = array( + // 'value' = serialize(array()) + 'value' => 'a:0:{}' ); // Show all flags (including flags set by other mail programs)? diff --git a/imp/js/compose-dimp.js b/imp/js/compose-dimp.js index 78aafcae8..51e410715 100644 --- a/imp/js/compose-dimp.js +++ b/imp/js/compose-dimp.js @@ -281,8 +281,8 @@ var DimpCompose = { case 'sendMessage': if (this.is_popup && DimpCore.base) { - if (d.reply_type) { - DimpCore.base.DimpBase.flag(d.reply_type == 'forward' ? '$forwarded' : '\\answered', true, { uid: d.uid, mailbox: d.reply_folder, noserver: true }); + if (d.flag) { + DimpCore.base.DimpBase.flagCallback(d); } if (d.mailbox) { @@ -294,7 +294,7 @@ var DimpCompose = { } if (d.log) { - DimpCore.base.DimpBase.updateMsgLog(d.log, { uid: d.uid, mailbox: d.reply_folder }); + DimpCore.base.DimpBase.updateMsgLog(d.log, { uid: d.uid, mailbox: d.mbox }); } if (!DIMP.conf_compose.qreply) { diff --git a/imp/js/dimpbase.js b/imp/js/dimpbase.js index fe00bc799..4b82146a2 100644 --- a/imp/js/dimpbase.js +++ b/imp/js/dimpbase.js @@ -316,7 +316,6 @@ var DimpBase = { // r = ViewPort row data msgWindow: function(r) { - this.updateSeenUID(r, 1); var url = DIMP.conf.URI_MESSAGE; url += (url.include('?') ? '&' : '?') + $H({ folder: r.view, @@ -414,7 +413,7 @@ var DimpBase = { if (r.flag) { r.flag.each(function(a) { var ptr = DIMP.conf.flags[a]; - if (ptr.p) { + if (ptr.u) { if (!ptr.elt) { /* Until text-overflow is supported on all * browsers, need to truncate label text @@ -423,12 +422,14 @@ var DimpBase = { } r.subjectdata += ptr.elt; } else { - if (!ptr.elt) { - ptr.elt = '
'; - } - r.status += ptr.elt; + if (ptr.c) { + if (!ptr.elt) { + ptr.elt = '
'; + } + r.status += ptr.elt; - r.VP_bg.push(ptr.c); + r.VP_bg.push(ptr.c); + } if (ptr.b) { bg = ptr.b; @@ -505,7 +506,7 @@ var DimpBase = { } else if (this.search.flag) { p.update({ qsearchflag: this.search.flag, - qsearchflagnot: Number(this.convertFlag(this.search.flag, this.search.not)) + qsearchflagnot: Number(this.search.not) }); } else { p.set('qsearch', $F('qsearch_input')); @@ -675,6 +676,8 @@ var DimpBase = { $('ctx_flag').childElements().each(function(c) { [ c ].invoke(flags.include(c.retrieve('flag')) ? 'show' : 'hide'); }); + } else { + $('ctx_flag').childElements().invoke('show'); } }.bindAsEventListener(this)); @@ -780,7 +783,11 @@ var DimpBase = { case 'ctx_folder_seen': case 'ctx_folder_unseen': - this.flagAll('\\seen', id == 'ctx_folder_seen', e.findElement('LI').retrieve('mbox')); + DimpCore.doAction('flagAll', { + add: Number(id == 'ctx_folder_seen'), + flags: Object.toJSON([ '\\seen' ]), + mbox: e.findElement('LI').retrieve('mbox') + }); break; case 'ctx_folder_poll': @@ -944,7 +951,7 @@ var DimpBase = { this.go('folder:' + DIMP.conf.fsearchid); } else if (menu.endsWith('_setflag') || menu.endsWith('_unsetflag')) { flag = elt.retrieve('flag'); - this.flag(flag, this.convertFlag(flag, menu.endsWith('_setflag'))); + this.flag(flag, menu.endsWith('_setflag')); } else if (menu.endsWith('_flag') || menu.endsWith('_flagnot')) { this.search = { flag: elt.retrieve('flag'), @@ -1072,18 +1079,18 @@ var DimpBase = { a.store('filter', filter); }, - contextAddFlag: function(flag, f) + contextAddFlag: function(flag, f, id) { var a = new Element('A'), style = {}; - if (f.p) { + if (f.u) { style.backgroundColor = f.b.escapeHTML(); } - $('ctx_flag').insert( + $(id).insert( a.insert( - new Element('SPAN', { className: 'iconImg' }).addClassName(f.c.escapeHTML()).setStyle(style) + new Element('SPAN', { className: 'iconImg' }).addClassName(f.i ? f.i.escapeHTML() : f.c.escapeHTML()).setStyle(style) ).insert( f.l.escapeHTML() ) @@ -1235,12 +1242,6 @@ var DimpBase = { pp_uid = this._getPPId(data.imapuid, data.view); if (this.ppfifo.indexOf(pp_uid) != -1) { - // There is a chance that the message may have been marked - // as unseen since first being viewed. If so, we need to - // explicitly flag as seen here. TODO? - if (!this.hasFlag('\\seen', data)) { - this.flag('\\seen', true); - } return this._loadPreviewCallback(this.ppcache[pp_uid]); } } @@ -1252,7 +1253,7 @@ var DimpBase = { _loadPreviewCallback: function(resp) { - var bg, ppuid, row, search, tmp, + var bg, ppuid, tmp, vs, pm = $('previewMsg'), r = resp.response.preview, t = $('msgHeadersContent').down('THEAD'); @@ -1260,14 +1261,6 @@ var DimpBase = { bg = (this.pp && (this.pp.imapuid != r.uid || this.pp.view != r.mailbox)); - if (!r.error) { - search = this.viewport.getSelection().search({ imapuid: { equal: [ r.uid ] }, view: { equal: [ r.mailbox ] } }); - if (search.size()) { - row = search.get('dataob').first(); - this.updateSeenUID(row, 1); - } - } - if (r.error || this.viewport.getSelected().size() != 1) { if (!bg) { if (r.error) { @@ -1278,6 +1271,8 @@ var DimpBase = { return; } + vs = this.viewport.getSelection(); + // Store in cache. ppuid = this._getPPId(r.uid, r.mailbox); this._expirePPCache([ ppuid ]); @@ -1329,7 +1324,7 @@ var DimpBase = { } // Toggle resume link - [ $('msg_resume_draft').up() ].invoke(this.viewport.getSelection().get('dataob').first().draft ? 'show' : 'hide'); + [ $('msg_resume_draft').up() ].invoke(vs.get('dataob').first().draft ? 'show' : 'hide'); $('messageBody').update(r.msgtext); this.loadingImg('msg', false); @@ -1341,7 +1336,7 @@ var DimpBase = { eval(r.js.join(';')); } - this.setHash('msg:' + row.view + ':' + row.imapuid); + this.setHash('msg:' + r.mailbox + ':' + r.uid); }, _stripAttachmentCallback: function(r) @@ -1453,25 +1448,6 @@ var DimpBase = { return uid + '|' + mailbox; }, - // Labeling functions - updateSeenUID: function(r, setflag) - { - var isunseen = !this.hasFlag('\\seen', r), - sel, unseen; - - if ((setflag && !isunseen) || (!setflag && isunseen)) { - return false; - } - - sel = this.viewport.createSelection('dataob', r); - unseen = this.getUnseenCount(r.view); - - unseen += setflag ? -1 : 1; - this.updateFlag(sel, '\\seen', setflag); - - this.updateUnseenStatus(r.view, unseen); - }, - // mbox = (string) getUnseenCount: function(mbox) { @@ -2446,12 +2422,27 @@ var DimpBase = { } }, - _flagAllCallback: function(r) + flagCallback: function(r) { - if (r.response && - r.response.mbox == this.folder) { - r.response.flags.each(function(f) { - this.updateFlag(this.viewport.createSelectionBuffer(), f, r.response.set); + if (!r.flag || + r.flag.mbox != this.folder) { + return; + } + + var f = r.flag, + sb = f.uids + ? this.viewport.createSelection('uid', DimpCore.parseRangeString(f.uids)[f.mbox]) + : this.viewport.createSelectionBuffer(); + + if (f.add) { + f.add.each(function(f) { + this.updateFlag(sb, f, true); + }, this); + } + + if (f.remove) { + f.remove.each(function(f) { + this.updateFlag(sb, f, false); }, this); } }, @@ -2931,86 +2922,42 @@ var DimpBase = { deleteMsg: function(opts) { opts = opts || {}; - var vs = this._getFlagSelection(opts); - - // Make sure that any given row is not deleted more than once. Need to - // explicitly mark here because message may already be flagged deleted - // when we load page (i.e. switching to using trash folder). - vs = vs.search({ isdel: { notequal: [ true ] } }); - if (!vs.size()) { - return; - } - vs.set({ isdel: true }); - - opts.vs = vs; + opts.vs = this._getFlagSelection(opts); this._doMsgAction('deleteMessages', opts, {}); - this.updateFlag(vs, '\\deleted', true); + this.updateFlag(opts.vs, '\\deleted', true); }, // flag = (string) IMAP flag name - // set = (boolean) True to set flag - // opts = (Object) 'mailbox', 'noserver', 'uid' - flag: function(flag, set, opts) + // add = (boolean) True to add flag + // opts = (Object) 'mailbox', 'uid' + flag: function(flag, add, opts) { - opts = opts || {}; - var flags = [ (set ? '' : '-') + flag ], - vs = this._getFlagSelection(opts); + var vs = this._getFlagSelection(opts || {}); if (!vs.size()) { return; } - switch (flag) { - case '\\answered': - if (set) { - this.updateFlag(vs, '\\flagged', false); - flags.push('-\\flagged'); - } - break; - - case '\\deleted': - vs.set({ isdel: false }); - break; + this.updateFlag(vs, flag, add); - case '\\seen': - vs.get('dataob').each(function(s) { - this.updateSeenUID(s, set); - }, this); - break; - } - - this.updateFlag(vs, flag, set); - if (!opts.noserver) { - DimpCore.doAction('flagMessages', this.viewport.addRequestParams({ flags: Object.toJSON(flags), view: this.folder }), { uids: vs }); - } - }, - - // type = (string) 'seen' or 'unseen' - // mbox = (string) The mailbox to flag - flagAll: function(type, set, mbox) - { - DimpCore.doAction('flagAll', { flags: Object.toJSON([ type ]), set: Number(set), mbox: mbox }, { callback: this._flagAllCallback.bind(this) }); + DimpCore.doAction('flagMessages', this.viewport.addRequestParams({ + add: Number(add), + flags: Object.toJSON([ flag ]), + view: this.folder + }), { + uids: vs + }); }, hasFlag: function(f, r) { - return this.convertFlag(f, r.flag ? r.flag.include(f) : false); - }, - - convertFlag: function(f, set) - { - /* For some flags, we need to do an inverse match (e.g. knowing a - * message is SEEN is not as important as knowing the message lacks - * the SEEN FLAG). This function will determine if, for a given flag, - * the inverse action should be taken on it. */ - return DIMP.conf.flags[f].n ? !set : set; + return (r.flag ? r.flag.include(f) : false); }, updateFlag: function(vs, flag, add) { var s = {}; - add = this.convertFlag(flag, add); vs.get('dataob').each(function(ob) { this._updateFlag(ob, flag, add); @@ -3146,8 +3093,8 @@ var DimpBase = { }); DM.addSubMenu('ctx_qsearchopts_by', 'ctx_qsearchby'); DM.addSubMenu('ctx_qsearchopts_filter', 'ctx_filter'); - DM.addSubMenu('ctx_qsearchopts_flag', 'ctx_flag'); - DM.addSubMenu('ctx_qsearchopts_flagnot', 'ctx_flag'); + DM.addSubMenu('ctx_qsearchopts_flag', 'ctx_flag_search'); + DM.addSubMenu('ctx_qsearchopts_flagnot', 'ctx_flag_search'); /* Create flag entries. */ DIMP.conf.filters_o.each(function(f) { @@ -3197,7 +3144,10 @@ var DimpBase = { /* Create flag entries. */ DIMP.conf.flags_o.each(function(f) { if (DIMP.conf.flags[f].s) { - this.contextAddFlag(f, DIMP.conf.flags[f]); + this.contextAddFlag(f, DIMP.conf.flags[f], 'ctx_flag_search'); + } + if (DIMP.conf.flags[f].a) { + this.contextAddFlag(f, DIMP.conf.flags[f], 'ctx_flag'); } }, this); @@ -3331,6 +3281,7 @@ DimpCore.onDoActionComplete = function(r) { if (DimpBase.viewport) { DimpBase.viewport.parseJSONResponse(r); } + DimpBase.flagCallback(r); DimpBase.pollCallback(r); }; diff --git a/imp/js/dimpcore.js b/imp/js/dimpcore.js index 362b0803f..9b6392814 100644 --- a/imp/js/dimpcore.js +++ b/imp/js/dimpcore.js @@ -471,7 +471,7 @@ var DimpCore = { reloadMessage: function(params) { - if (typeof DimpFullmessage != 'undefined') { + if (typeof DimpMessage != 'undefined') { window.location = this.addURLParam(document.location.href, params); } else { DimpBase.loadPreview(null, params); diff --git a/imp/js/fullmessage-dimp.js b/imp/js/message-dimp.js similarity index 91% rename from imp/js/fullmessage-dimp.js rename to imp/js/message-dimp.js index 0779a3e75..fa047f17b 100644 --- a/imp/js/fullmessage-dimp.js +++ b/imp/js/message-dimp.js @@ -5,7 +5,7 @@ * did not receive this file, see http://www.fsf.org/copyleft/gpl.html. */ -var DimpFullmessage = { +var DimpMessage = { // Variables defaulting to empty/false: mailbox, uid quickreply: function(type) @@ -230,8 +230,16 @@ var DimpFullmessage = { DimpCore.updateMsgLog(this.log); } - if (this.strip && DimpCore.base) { - DimpCore.base.DimpBase.poll(); + if (DimpCore.base) { + if (this.strip) { + DimpCore.base.DimpBase.poll(); + } else if (this.poll) { + DimpCore.base.DimpBase.pollCallback({ poll: this.poll }); + } + + if (this.flag) { + DimpCore.base.DimpBase.flagCallback({ flag: this.flag }); + } } $('dimpLoading').hide(); @@ -243,11 +251,11 @@ var DimpFullmessage = { }; /* ContextSensitive functions. */ -DimpCore.contextOnClick = DimpCore.contextOnClick.wrap(DimpFullmessage.contextOnClick.bind(DimpFullmessage)); +DimpCore.contextOnClick = DimpCore.contextOnClick.wrap(DimpMessage.contextOnClick.bind(DimpMessage)); /* Click handler. */ -DimpCore.clickHandler = DimpCore.clickHandler.wrap(DimpFullmessage.clickHandler.bind(DimpFullmessage)); +DimpCore.clickHandler = DimpCore.clickHandler.wrap(DimpMessage.clickHandler.bind(DimpMessage)); /* Attach event handlers. */ -document.observe('dom:loaded', DimpFullmessage.onDomLoad.bind(DimpFullmessage)); -Event.observe(window, 'resize', DimpFullmessage.resizeWindow.bind(DimpFullmessage)); +document.observe('dom:loaded', DimpMessage.onDomLoad.bind(DimpMessage)); +Event.observe(window, 'resize', DimpMessage.resizeWindow.bind(DimpMessage)); diff --git a/imp/lib/Ajax/Application.php b/imp/lib/Ajax/Application.php index bb87a471b..97e8785d6 100644 --- a/imp/lib/Ajax/Application.php +++ b/imp/lib/Ajax/Application.php @@ -215,42 +215,37 @@ class IMP_Ajax_Application extends Horde_Core_Ajax_Application * * Variables used: *
-     * 'flags' - (string) The flags to set (JSON serialized array).
+     * 'add' - (integer) Add the flags?
+     * 'flags' - (string) The IMAP flags to add/remove (JSON serialized
+     *           array).
      * 'mbox' - (string) The full malbox name.
-     * 'set' - (integer) Set the flags?
      * 
* * @return mixed False on failure, or an object with the following * entries: *
-     * 'flags' - (array) The list of flags that were set.
-     * 'mbox' - (string) The full mailbox name.
+     * 'flag' - (object) See flagEntry().
      * 'poll' - (array) Mailbox names as the keys, number of unseen messages
      *          as the values.
-     * 'set' - (integer) 1 if the flag was set. Unset otherwise.
      * 
*/ public function flagAll() { $flags = Horde_Serialize::unserialize($this->_vars->flags, Horde_Serialize::JSON); - if (!$this->_vars->mbox || empty($flags)) { + if (!$this->_vars->mbox || + empty($flags) || + !$GLOBALS['injector']->getInstance('IMP_Message')->flagAllInMailbox($flags, array($this->_vars->mbox), $this->_vars->add)) { return false; } - $result = $GLOBALS['injector']->getInstance('IMP_Message')->flagAllInMailbox($flags, array($this->_vars->mbox), $this->_vars->set); + $result = new stdClass; - if ($result) { - $result = new stdClass; - $result->flags = $flags; - $result->mbox = $this->_vars->mbox; - if ($this->_vars->set) { - $result->set = 1; - } + /* Get list of flags that were also affected by this flag + * change. */ + $result->flag = $this->flagEntry($flags, $this->_vars->add, $this->_vars->mbox); - $poll = $this->_getPollInformation($this->_vars->mbox); - if (!empty($poll)) { - $result->poll = array($this->_vars->mbox => $poll[$this->_vars->mbox]); - } + if ($poll = $this->pollEntry($this->_vars->mbox)) { + $result->poll = $poll; } return $result; @@ -453,11 +448,7 @@ class IMP_Ajax_Application extends Horde_Core_Ajax_Application $changed = false; $result = new stdClass; - $result->poll = array(); - - foreach ($GLOBALS['injector']->getInstance('IMP_Injector_Factory_Imap')->create()->statusMultiple($GLOBALS['injector']->getInstance('IMP_Imap_Tree')->getPollList(), Horde_Imap_Client::STATUS_UNSEEN) as $key => $val) { - $result->poll[$key] = intval($val['unseen']); - } + $result->poll = $this->pollEntry(); if ($this->_vars->view && ($changed = $this->_changed())) { @@ -650,7 +641,7 @@ class IMP_Ajax_Application extends Horde_Core_Ajax_Application /* Update poll information for destination folder if necessary. * Poll information for current folder will be added by * _generateDeleteResult() call above. */ - if ($poll = $this->_getPollInformation($this->_vars->mboxto)) { + if ($poll = $this->pollEntry($this->_vars->mboxto)) { $result->poll = array_merge(isset($result->poll) ? $result->poll : array(), $poll); } } else { @@ -687,7 +678,7 @@ class IMP_Ajax_Application extends Horde_Core_Ajax_Application } if ($result = $GLOBALS['injector']->getInstance('IMP_Message')->copy($this->_vars->mboxto, 'copy', $indices)) { - if ($poll = $this->_getPollInformation($this->_vars->mboxto)) { + if ($poll = $this->pollEntry($this->_vars->mboxto)) { $result->poll = array_merge(isset($result->poll) ? $result->poll : array(), $poll); } } else { @@ -703,6 +694,7 @@ class IMP_Ajax_Application extends Horde_Core_Ajax_Application * See the list of variables needed for _changed() and * _checkUidvalidity(). Additional variables used: *
+     * 'add' - (integer) Set the flag?
      * 'flags' - (string) The flags to set (JSON serialized array).
      * 'uid' - (string) Indices of the messages to flag (IMAP sequence
      *         string).
@@ -711,6 +703,8 @@ class IMP_Ajax_Application extends Horde_Core_Ajax_Application
      * @return mixed  False on failure, or an object with the following
      *                entries:
      * 
+     * 'flag' - (object) See flagEntry().
+     * 'poll' - (array) See pollEntry().
      * 'ViewPort' - (object) See _viewPortData().
      * 
*/ @@ -728,37 +722,28 @@ class IMP_Ajax_Application extends Horde_Core_Ajax_Application } $flags = Horde_Serialize::unserialize($this->_vars->flags, Horde_Serialize::JSON); - $set = $notset = array(); - foreach ($flags as $val) { - if ($val[0] == '-') { - $notset[] = substr($val, 1); - } else { - $set[] = $val; - } + if (!$GLOBALS['injector']->getInstance('IMP_Message')->flag($flags, $indices, $this->_vars->add)) { + return $this->_checkUidvalidity(); } - if (!empty($set)) { - $result = $GLOBALS['injector']->getInstance('IMP_Message')->flag($set, $indices, true); - } + $result = new stdClass; + list($mbox, $uids) = $indices->getSingle(true); + $result->flag = $this->flagEntry($flags, $this->_vars->add, $mbox, $uids); - if (!empty($notset)) { - $result = $GLOBALS['injector']->getInstance('IMP_Message')->flag($notset, $indices, false); + if (in_array('\\seen', $flags) && ($poll = $this->pollEntry($mbox))) { + $result->poll = $poll; } - if ($result) { - $result = new stdClass; - if ($change) { - $result->ViewPort = $this->_viewPortData(true); - } else { - $result->ViewPort = new stdClass; - $result->ViewPort->updatecacheid = $GLOBALS['injector']->getInstance('IMP_Injector_Factory_MailboxList')->create($this->_vars->view)->getCacheID($this->_vars->view); - $result->ViewPort->view = $this->_vars->view; - } - return $result; + if ($change) { + $result->ViewPort = $this->_viewPortData(true); + } else { + $result->ViewPort = new stdClass; + $result->ViewPort->updatecacheid = $GLOBALS['injector']->getInstance('IMP_Injector_Factory_MailboxList')->create($this->_vars->view)->getCacheID($this->_vars->view); + $result->ViewPort->view = $this->_vars->view; } - return $this->_checkUidvalidity(); + return $result; } /** @@ -965,6 +950,9 @@ class IMP_Ajax_Application extends Horde_Core_Ajax_Application * @return mixed False on failure, or an object with the following * entries: *
+     * 'flag' - (object) See flagEntry().
+     * 'poll' - (array) Mailbox names as the keys, number of unseen messages
+     *          as the values.
      * 'preview' - (object) Return from IMP_View_ShowMessage::showMessage().
      * 'ViewPort' - (object) See _viewPortData(). (Only returns updatecacheid
      *                       entry - don't do mailbox poll here).
@@ -1005,6 +993,13 @@ class IMP_Ajax_Application extends Horde_Core_Ajax_Application
                     $result->ViewPort->view = $this->_vars->view;
                 }
             }
+
+            if ($poll = $this->pollEntry($this->_vars->view)) {
+                $result->poll = $poll;
+            }
+
+            /* Add changed flag information. */
+            $result->flag = $this->flagEntry(array('\\seen'), true, $mbox, $idx);
         } catch (Horde_Imap_Client_Exception $e) {
             $result->preview->error = $e->getMessage();
             $result->preview->errortype = 'horde.error';
@@ -1641,14 +1636,14 @@ class IMP_Ajax_Application extends Horde_Core_Ajax_Application
      * 'action' - (string) The AJAX action string
      * 'draft_delete' - (integer) TODO
      * 'encryptjs' - (array) Javascript to run after encryption failure.
+     * 'flag' - (object) See flagEntry().
      * 'identity' - (integer) If set, this is the identity that is tied to
      *              the current recipient address.
      * 'log' - (array) TODO
      * 'mailbox' - (array) TODO
-     * 'reply_folder' - (string) TODO
-     * 'reply_type' - (string) TODO
+     * 'mbox' - (string) Mailbox of original message.
      * 'success' - (integer) 1 on success, 0 on failure.
-     * 'uid' - (integer) TODO
+     * 'uid' - (integer) IMAP UID of original message.
      * 
*/ public function sendMessage() @@ -1663,13 +1658,6 @@ class IMP_Ajax_Application extends Horde_Core_Ajax_Application $headers['replyto'] = $identity->getValue('replyto_addr'); - $result->uid = $imp_compose->getMetadata('uid'); - - if ($reply_type = $imp_compose->getMetadata('reply_type')) { - $result->reply_folder = $imp_compose->getMetadata('mailbox'); - $result->reply_type = $reply_type; - } - /* Use IMP_Tree to determine whether the sent mail folder was * created. */ $imptree = $GLOBALS['injector']->getInstance('IMP_Imap_Tree'); @@ -1749,6 +1737,21 @@ class IMP_Ajax_Application extends Horde_Core_Ajax_Application } } + $result->mbox = $imp_compose->getMetadata('mailbox'); + $result->uid = $imp_compose->getMetadata('uid'); + + switch ($imp_compose->getMetadata('reply_type')) { + case 'forward': + $result->flag = $this->flagEntry(array('$forwarded'), true, $result->mbox, $result->uid); + break; + + case 'reply': + case 'reply_all': + case 'reply_list': + $result->flag = $this->flagEntry(array('\\answered'), true, $result->mbox, $result->uid); + break; + } + $imp_compose->destroy('send'); $result->mailbox = $this->_getMailboxResponse($imptree); @@ -1807,6 +1810,69 @@ class IMP_Ajax_Application extends Horde_Core_Ajax_Application } /** + * Generate flag updated entry. + * + * @param array $flags List of flags that have changed. + * @param boolean $add Were the flags added? + * @param string $mbox Mailbox where flags changed. + * @param string $uids IMAP UIDs of the changed flags. + * + * @return stdClass Object with these properties: + *
+     * 'add' - (array) The list of flags that were added.
+     * 'mbox' - (string) The full mailbox name.
+     * 'remove' - (array) The list of flags that were removed.
+     * 'uids' - (string) Indices of the messages that have changed (IMAP
+     *          sequence string); if empty, all messages in mailbox have
+     *          changed.
+     * 
+ */ + static public function flagEntry($flags, $add, $mbox, $uids = null) + { + $changed = $GLOBALS['injector']->getInstance('IMP_Flags')->changed($flags, $add); + + $result = new stdClass; + if (!empty($changed['add'])) { + $result->add = array_map('strval', $changed['add']); + } + $result->mbox = $mbox; + if (!empty($changed['remove'])) { + $result->remove = array_map('strval', $changed['remove']); + } + if (!is_null($uids)) { + $result->uids = strval(new IMP_Indices($mbox, $uids)); + } + + return $result; + } + + /** + * Generate poll information for mailboxes. + * + * @param string $mbox The full mailbox name. If null, all polled + * mailboxes are returned. + * + * @return array Keys are mailbox names, values are the number of unseen + * messages. + */ + static public function pollEntry($mbox = null) + { + $imaptree = $GLOBALS['injector']->getInstance('IMP_Imap_Tree'); + + if (is_null($mbox)) { + $result = array(); + foreach ($GLOBALS['injector']->getInstance('IMP_Injector_Factory_Imap')->create()->statusMultiple($imaptree->getPollList(), Horde_Imap_Client::STATUS_UNSEEN) as $key => $val) { + $result[$key] = intval($val['unseen']); + } + return $result; + } + + return $imaptree[$mbox]->polled + ? array($mbox => $imaptree[$mbox]->poll_info->unseen) + : array(); + } + + /** * Setup environment for dimp compose actions. * * Variables used: @@ -1990,8 +2056,7 @@ class IMP_Ajax_Application extends Horde_Core_Ajax_Application $result->ViewPort->view = $this->_vars->view; } - $poll = $this->_getPollInformation($this->_vars->view); - if (!empty($poll)) { + if ($poll = $this->pollEntry($this->_vars->view)) { $result->poll = $poll; } @@ -2092,23 +2157,6 @@ class IMP_Ajax_Application extends Horde_Core_Ajax_Application } /** - * Generate poll information for a single mailbox. - * - * @param string $mbox The full mailbox name. - * - * @return array Key is the mailbox name, value is the number of unseen - * messages. - */ - protected function _getPollInformation($mbox) - { - $imaptree = $GLOBALS['injector']->getInstance('IMP_Imap_Tree'); - - return $imaptree[$mbox]->polled - ? array($mbox => $imaptree[$mbox]->poll_info->unseen) - : array(); - } - - /** * Generate quota information. * * @return array 'p': Quota percentage; 'm': Quota message diff --git a/imp/lib/Api.php b/imp/lib/Api.php index 52ba1fe16..e787edfc8 100644 --- a/imp/lib/Api.php +++ b/imp/lib/Api.php @@ -223,8 +223,7 @@ class IMP_Api extends Horde_Registry_Api * @param string $mailbox If set, returns the list of flags filtered by * what the mailbox allows. * - * @return array See IMP_Imap_Flags::getList() for the output. The - * 'f' key will be set. + * @return array A list of IMP_Flag_Base objects. */ public function flagList($mailbox = null) { @@ -232,16 +231,10 @@ class IMP_Api extends Horde_Registry_Api return array(); } - $opts = array( - 'fgcolor' => true, + return $GLOBALS['injector']->getInstance('IMP_Flags')->getList(array( 'imap' => true, - ); - - if (!is_null($mailbox)) { - $opts['mailbox'] = $mailbox; - } - - return $GLOBALS['injector']->getInstance('IMP_Imap_Flags')->getList($opts); + 'mailbox' => $mailbox + )); } } diff --git a/imp/lib/Application.php b/imp/lib/Application.php index 5dd2effc0..8c904aa63 100644 --- a/imp/lib/Application.php +++ b/imp/lib/Application.php @@ -100,6 +100,7 @@ class IMP_Application extends Horde_Registry_Application 'IMP_AuthImap' => 'IMP_Injector_Factory_AuthImap', 'IMP_Crypt_Pgp' => 'IMP_Injector_Factory_Pgp', 'IMP_Crypt_Smime' => 'IMP_Injector_Factory_Smime', + 'IMP_Flags' => 'IMP_Injector_Factory_Flags', 'IMP_Identity' => 'IMP_Injector_Factory_Identity', 'IMP_Imap_Tree' => 'IMP_Injector_Factory_Imaptree', 'IMP_Mail' => 'IMP_Injector_Factory_Mail', diff --git a/imp/lib/Flag/Base.php b/imp/lib/Flag/Base.php new file mode 100644 index 000000000..0dc599bc3 --- /dev/null +++ b/imp/lib/Flag/Base.php @@ -0,0 +1,229 @@ + + * @category Horde + * @license http://www.fsf.org/copyleft/gpl.html GPL + * @package IMP + */ +abstract class IMP_Flag_Base implements Serializable +{ + /* Default background color. */ + const DEFAULT_BG = '#fff'; + + /** + * The abbreviation. + * + * @var string + */ + protected $_abbreviation = ''; + + /** + * The background color. + * + * @var string + */ + protected $_bgcolor = ''; + + /** + * Is this flag settable by the user? + * + * @var boolean + */ + protected $_canset = false; + + /** + * The CSS class. + * + * @var string + */ + protected $_css = ''; + + /** + * The CSS class for the icon. + * + * @var string + */ + protected $_cssIcon = ''; + + /** + * Unique ID. + * + * @var string + */ + protected $_id = ''; + + /** + * Get object properties. + * + * @param string $name Available properties: + *
+     * 'abbreviation' - (string) The abbreviation to use in the mimp view.
+     * 'bgcolor' - (string) The background color.
+     * 'bgdefault' - (boolean) Is the backgroud color the default?
+     * 'canset' - (boolean) Can this flag be set by the user?
+     * 'css' - (string) The CSS class for the icon when the flag is set.
+     * 'cssicon' - (string) The CSS class for the icon.
+     * 'div' - (string) Return DIV HTML to output the icon for use in a
+     *         mailbox row.
+     * 'fgcolor' - (string) The foreground (text) color.
+     * 'form_set' - (string) Form value to use when setting flag.
+     * 'form_unset' - (string) Form value to use when unsetting flag.
+     * 'id' - (string) Unique ID.
+     * 'label' - (string) The query label.
+     * 
+ * + * @return mixed Property value. + */ + public function __get($name) + { + switch ($name) { + case 'abbreviation': + return $this->_abbreviation; + + case 'bgcolor': + return $this->_bgcolor + ? $this->_bgcolor + : self::DEFAULT_BG; + + case 'bgdefault': + return ($this->bgcolor == self::DEFAULT_BG); + + case 'canset': + return $this->_canset; + + case 'css': + return $this->_css; + + case 'cssicon': + return $this->_cssIcon + ? $this->_cssIcon + : $this->_css; + + case 'div': + return $this->_css + ? '
' + : ''; + + case 'fgcolor': + return (Horde_Image::brightness($this->bgcolor) < 128) + ? '#f6f6f6' + : '#000'; + + case 'form_set': + return $this->id; + + case 'form_unset': + return '0\\' . $this->id; + + case 'id': + return $this->_id; + + case 'label': + return $this->getLabel(); + } + } + + /** + * Set properties. + * + * @param string $name Available properties: + *
+     * 'bgcolor' - (string) The background color.
+     * 
+ * @param string $value Property value. + */ + public function __set($name, $value) + { + switch ($name) { + case 'bgcolor': + $this->_bgcolor = ($value == self::DEFAULT_BG) + ? '' + : $value; + break; + } + } + + /** + * Given a list of flag objects, determines if this flag's status has + * changed. + * + * @param array $obs A list of IMP_Flag_Base objects. + * @param boolean $add True if these flags were added, false if they were + * removed. + * + * @return mixed Null if no change, true if flag is added, false if flag + * is removed. + */ + public function changed($obs, $add) + { + return null; + } + + /** + * Return the flag label. + * + * @param boolean $set Return label for setting the flag? + * + * @return string The label. + */ + public function getLabel($set = true) + { + return $set + ? $this->_getLabel() + : sprintf(_("Not %s"), $this->_getLabel()); + } + + /** + * Determines if the flag exists given some input data. + * + * @param mixed $data The input data to check. + * + * @return boolean True if flag exists. + */ + abstract public function match($data); + + /** + * Return the flag label. + * Necessary evil as gettext strings can not be set directly to object + * properties. + * + * @return string The label. + */ + abstract protected function _getLabel(); + + /* Magic methods. */ + + /** + * String representation of the object. + * + * @return string String representation (Flag ID). + */ + public function __toString() + { + return $this->id; + } + + /* Serializable methods. */ + + /** + */ + public function serialize() + { + return $this->_bgcolor; + } + + /** + */ + public function unserialize($data) + { + $this->_bgcolor = $data; + } + +} diff --git a/imp/lib/Flag/Imap.php b/imp/lib/Flag/Imap.php new file mode 100644 index 000000000..e0bee2830 --- /dev/null +++ b/imp/lib/Flag/Imap.php @@ -0,0 +1,50 @@ + + * @category Horde + * @license http://www.fsf.org/copyleft/gpl.html GPL + * @package IMP + */ +abstract class IMP_Flag_Imap extends IMP_Flag_Base +{ + /** + * The IMAP flag string used on the server. + * + * @var string + */ + protected $_imapflag; + + /** + * @param string $name Additional properties: + *
+     * 'imapflag' - (string) The IMAP flag string.
+     * 
+ */ + public function __get($name) + { + switch ($name) { + case 'id': + case 'imapflag': + return $this->_imapflag; + + default: + return parent::__get($name); + } + } + + /** + * @param array $input List of IMAP flags. + */ + public function match($data) + { + return in_array($this->imapflag, $data); + } + +} diff --git a/imp/lib/Flag/Imap/Answered.php b/imp/lib/Flag/Imap/Answered.php new file mode 100644 index 000000000..c7ec23f1d --- /dev/null +++ b/imp/lib/Flag/Imap/Answered.php @@ -0,0 +1,36 @@ + + * @category Horde + * @license http://www.fsf.org/copyleft/gpl.html GPL + * @package IMP + */ +class IMP_Flag_Imap_Answered extends IMP_Flag_Imap +{ + /** + */ + protected $_bgcolor = '#cfc'; + + /** + */ + protected $_css = 'flagAnswered'; + + /** + */ + protected $_imapflag = '\\answered'; + + /** + */ + protected function _getLabel() + { + return _("Answered"); + } + +} diff --git a/imp/lib/Flag/Imap/Deleted.php b/imp/lib/Flag/Imap/Deleted.php new file mode 100644 index 000000000..bf87a84ae --- /dev/null +++ b/imp/lib/Flag/Imap/Deleted.php @@ -0,0 +1,40 @@ + + * @category Horde + * @license http://www.fsf.org/copyleft/gpl.html GPL + * @package IMP + */ +class IMP_Flag_Imap_Deleted extends IMP_Flag_Imap +{ + /** + */ + protected $_abbreviation = 'D'; + + /** + */ + protected $_bgcolor = '#999'; + + /** + */ + protected $_css = 'flagDeleted'; + + /** + */ + protected $_imapflag = '\\deleted'; + + /** + */ + protected function _getLabel() + { + return _("Deleted"); + } + +} diff --git a/imp/lib/Flag/Imap/Draft.php b/imp/lib/Flag/Imap/Draft.php new file mode 100644 index 000000000..39007f469 --- /dev/null +++ b/imp/lib/Flag/Imap/Draft.php @@ -0,0 +1,40 @@ + + * @category Horde + * @license http://www.fsf.org/copyleft/gpl.html GPL + * @package IMP + */ +class IMP_Flag_Imap_Draft extends IMP_Flag_Imap +{ + /** + */ + protected $_abbreviation = 'd'; + + /** + */ + protected $_bgcolor = '#ffd93d'; + + /** + */ + protected $_css = 'flagDraft'; + + /** + */ + protected $_imapflag = '\\draft'; + + /** + */ + protected function _getLabel() + { + return _("Draft"); + } + +} diff --git a/imp/lib/Flag/Imap/Flagged.php b/imp/lib/Flag/Imap/Flagged.php new file mode 100644 index 000000000..a197336ee --- /dev/null +++ b/imp/lib/Flag/Imap/Flagged.php @@ -0,0 +1,40 @@ + + * @category Horde + * @license http://www.fsf.org/copyleft/gpl.html GPL + * @package IMP + */ +class IMP_Flag_Imap_Flagged extends IMP_Flag_Imap +{ + /** + */ + protected $_bgcolor = '#fcc'; + + /** + */ + protected $_canset = true; + + /** + */ + protected $_css = 'flagFlagged'; + + /** + */ + protected $_imapflag = '\\flagged'; + + /** + */ + protected function _getLabel() + { + return _("Flagged for Followup"); + } + +} diff --git a/imp/lib/Flag/Imap/Forwarded.php b/imp/lib/Flag/Imap/Forwarded.php new file mode 100644 index 000000000..33ac8b379 --- /dev/null +++ b/imp/lib/Flag/Imap/Forwarded.php @@ -0,0 +1,36 @@ + + * @category Horde + * @license http://www.fsf.org/copyleft/gpl.html GPL + * @package IMP + */ +class IMP_Flag_Imap_Forwarded extends IMP_Flag_Imap +{ + /** + */ + protected $_bgcolor = '#bfdfdf'; + + /** + */ + protected $_css = 'flagForwarded'; + + /** + */ + protected $_imapflag = '$forwarded'; + + /** + */ + protected function _getLabel() + { + return _("Forwarded"); + } + +} diff --git a/imp/lib/Flag/Imap/Seen.php b/imp/lib/Flag/Imap/Seen.php new file mode 100644 index 000000000..26c10b31d --- /dev/null +++ b/imp/lib/Flag/Imap/Seen.php @@ -0,0 +1,37 @@ + + * @category Horde + * @license http://www.fsf.org/copyleft/gpl.html GPL + * @package IMP + */ +class IMP_Flag_Imap_Seen extends IMP_Flag_Imap +{ + /** + */ + protected $_canset = true; + + /** + */ + protected $_cssIcon = 'flagSeen'; + + /** + */ + protected $_imapflag = '\\seen'; + + /** + */ + protected function _getLabel() + { + return _("Seen"); + } + +} diff --git a/imp/lib/Flag/System.php b/imp/lib/Flag/System.php new file mode 100644 index 000000000..fcb52bec3 --- /dev/null +++ b/imp/lib/Flag/System.php @@ -0,0 +1,17 @@ + + * @category Horde + * @license http://www.fsf.org/copyleft/gpl.html GPL + * @package IMP + */ +abstract class IMP_Flag_System extends IMP_Flag_Base +{ +} diff --git a/imp/lib/Flag/System/Attachment.php b/imp/lib/Flag/System/Attachment.php new file mode 100644 index 000000000..2c2766b8e --- /dev/null +++ b/imp/lib/Flag/System/Attachment.php @@ -0,0 +1,46 @@ + + * @category Horde + * @license http://www.fsf.org/copyleft/gpl.html GPL + * @package IMP + */ +class IMP_Flag_System_Attachment extends IMP_Flag_System +{ + /** + */ + protected $_css = 'flagAttachmsg'; + + /** + */ + protected $_id = 'attach'; + + /** + */ + protected function _getLabel() + { + return _("Message has Attachments"); + } + + /** + * @param Horde_Mime_Headers $data Headers object for a message. + */ + public function match($data) + { + if (!($ctype = $data->getValue('content-type', Horde_Mime_Headers::VALUE_BASE))) { + return false; + } + + list($primary, $sub) = explode('/', $ctype, 2); + return (($primary == 'multipart') && + !in_array($sub, array('alternative', 'encrypt', 'related', 'signed'))); + } + +} diff --git a/imp/lib/Flag/System/Encrypted.php b/imp/lib/Flag/System/Encrypted.php new file mode 100644 index 000000000..806cbcdaa --- /dev/null +++ b/imp/lib/Flag/System/Encrypted.php @@ -0,0 +1,43 @@ + + * @category Horde + * @license http://www.fsf.org/copyleft/gpl.html GPL + * @package IMP + */ +class IMP_Flag_System_Encrypted extends IMP_Flag_System +{ + /** + */ + protected $_css = 'flagEncryptmsg'; + + /** + */ + protected $_id = 'encrypted'; + + /** + */ + protected function _getLabel() + { + return _("Message is Encrypted"); + } + + /** + * @param Horde_Mime_Headers $data Headers object for a message. + */ + public function match($data) + { + $ctype = $data->getValue('content-type', Horde_Mime_Headers::VALUE_BASE); + + return (($ctype == 'application/pkcs7-mime') || + ($ctype == 'multipart/encrypted')); + } + +} diff --git a/imp/lib/Flag/System/HighPriority.php b/imp/lib/Flag/System/HighPriority.php new file mode 100644 index 000000000..0ca3432d4 --- /dev/null +++ b/imp/lib/Flag/System/HighPriority.php @@ -0,0 +1,48 @@ + + * @category Horde + * @license http://www.fsf.org/copyleft/gpl.html GPL + * @package IMP + */ +class IMP_Flag_System_HighPriority extends IMP_Flag_System +{ + /** + */ + protected $_abbreviation = '!'; + + /** + */ + protected $_bgcolor = '#fcc'; + + /** + */ + protected $_css = 'flagHighpriority'; + + /** + */ + protected $_id = 'highp'; + + /** + */ + protected function _getLabel() + { + return _("High Priority"); + } + + /** + * @param Horde_Mime_Headers $data Headers object for a message. + */ + public function match($data) + { + return ($GLOBALS['injector']->getInstance('IMP_Ui_Headers')->getPriority($data) == 'high'); + } + +} diff --git a/imp/lib/Flag/System/LowPriority.php b/imp/lib/Flag/System/LowPriority.php new file mode 100644 index 000000000..9e912fc8d --- /dev/null +++ b/imp/lib/Flag/System/LowPriority.php @@ -0,0 +1,40 @@ + + * @category Horde + * @license http://www.fsf.org/copyleft/gpl.html GPL + * @package IMP + */ +class IMP_Flag_System_LowPriority extends IMP_Flag_System +{ + /** + */ + protected $_css = 'flagLowpriority'; + + /** + */ + protected $_id = 'lowp'; + + /** + */ + protected function _getLabel() + { + return _("Low Priority"); + } + + /** + * @param Horde_Mime_Headers $data Headers object for a message. + */ + public function match($data) + { + return ($GLOBALS['injector']->getInstance('IMP_Ui_Headers')->getPriority($data) == 'low'); + } + +} diff --git a/imp/lib/Flag/System/Personal.php b/imp/lib/Flag/System/Personal.php new file mode 100644 index 000000000..ef206921b --- /dev/null +++ b/imp/lib/Flag/System/Personal.php @@ -0,0 +1,54 @@ + + * @category Horde + * @license http://www.fsf.org/copyleft/gpl.html GPL + * @package IMP + */ +class IMP_Flag_System_Personal extends IMP_Flag_System +{ + /** + */ + protected $_css = 'flagPersonal'; + + /** + */ + protected $_id = 'personal'; + + /** + */ + protected function _getLabel() + { + return _("Personal"); + } + + /** + * @param mixed $data Either an array of To addresses as returned by + * Horde_Mime_Address::getAddressesFromObject() or the + * identity that matched the address list. + */ + public function match($data) + { + if (is_array($data)) { + $identity = $GLOBALS['injector']->getInstance('IMP_Identity'); + + foreach ($data as $val) { + if ($identity->hasAddress($val['inner'])) { + return true; + } + } + } else if (!is_null($data)) { + return true; + } + + return false; + } + +} diff --git a/imp/lib/Flag/System/Signed.php b/imp/lib/Flag/System/Signed.php new file mode 100644 index 000000000..80b8092aa --- /dev/null +++ b/imp/lib/Flag/System/Signed.php @@ -0,0 +1,40 @@ + + * @category Horde + * @license http://www.fsf.org/copyleft/gpl.html GPL + * @package IMP + */ +class IMP_Flag_System_Signed extends IMP_Flag_System +{ + /** + */ + protected $_css = 'flagSignedmsg'; + + /** + */ + protected $_id = 'signed'; + + /** + */ + protected function _getLabel() + { + return _("Message is Signed"); + } + + /** + * @param Horde_Mime_Headers $data Headers object for a message. + */ + public function match($data) + { + return ($data->getValue('content-type', Horde_Mime_Headers::VALUE_BASE) == 'multipart/signed'); + } + +} diff --git a/imp/lib/Flag/System/Unseen.php b/imp/lib/Flag/System/Unseen.php new file mode 100644 index 000000000..79809f845 --- /dev/null +++ b/imp/lib/Flag/System/Unseen.php @@ -0,0 +1,63 @@ + + * @category Horde + * @license http://www.fsf.org/copyleft/gpl.html GPL + * @package IMP + */ +class IMP_Flag_System_Unseen extends IMP_Flag_System +{ + /** + */ + protected $_abbreviation = 'U'; + + /** + */ + protected $_bgcolor = '#eef'; + + /** + */ + protected $_css = 'flagUnseen'; + + /** + */ + protected $_id = 'unseen'; + + /** + */ + protected function _getLabel() + { + return _("Unseen"); + } + + /** + */ + public function changed($obs, $add) + { + foreach ($obs as $val) { + if ($val instanceof IMP_Flag_Imap_Seen) { + return !$add; + } + } + + return null; + } + + /** + * @param array $data List of IMAP flags. + */ + public function match($data) + { + return !in_array('\\seen', $data); + } + +} diff --git a/imp/lib/Flag/User.php b/imp/lib/Flag/User.php new file mode 100644 index 000000000..b2b6e2324 --- /dev/null +++ b/imp/lib/Flag/User.php @@ -0,0 +1,102 @@ + + * @category Horde + * @license http://www.fsf.org/copyleft/gpl.html GPL + * @package IMP + */ +class IMP_Flag_User extends IMP_Flag_Imap +{ + /** + */ + protected $_canset = true; + + /** + */ + protected $_css = 'flagUser'; + + /** + * The flag label. + * + * @var string + */ + protected $_label; + + /** + * Constructor. + * + * @param string $label The label. + * @param string $flag The IMAP flag. + * @param string $bgcolor The background color. + */ + public function __construct($label, $flag = null, $bgcolor = null) + { + $this->label = $label; + $this->imapflag = is_null($flag) + ? $label + : $flag; + if (isset($bgcolor)) { + $this->bgcolor = $bgcolor; + } + } + + /** + */ + public function __set($name, $value) + { + switch ($name) { + case 'imapflag': + /* IMAP keywords must conform to RFC 3501 [9] (flag-keyword). + * Convert whitespace to underscore. */ + $this->_imapflag = $GLOBALS['injector']->getInstance('IMP_Injector_Factory_Imap')->create()->getUtils()->stripNonAtomChars(Horde_String::convertCharset(strtr($value, ' ', '_'), 'UTF-8', 'UTF7-IMAP')); + break; + + case 'label': + $this->_label = $value; + break; + + default: + parent::__set($name, $value); + break; + } + } + + /** + */ + protected function _getLabel() + { + return $this->_label; + } + + /* Serializable methods. */ + + /** + */ + public function serialize() + { + return json_encode(array( + parent::serialize(), + $this->_label, + $this->_imapflag + )); + } + + /** + */ + public function unserialize($data) + { + $data = json_decode($data, true); + + parent::unserialize($data[0]); + $this->_label = $data[1]; + $this->_imapflag = $data[2]; + } + +} diff --git a/imp/lib/Flags.php b/imp/lib/Flags.php new file mode 100644 index 000000000..371ccf0a6 --- /dev/null +++ b/imp/lib/Flags.php @@ -0,0 +1,397 @@ + + * @category Horde + * @license http://www.fsf.org/copyleft/gpl.html GPL + * @package IMP + */ +class IMP_Flags implements ArrayAccess, Serializable +{ + /** + * Has the object data changed? + * + * @var boolean + */ + public $changed = false; + + /** + * The list of internal flags. + * + * @var array + */ + protected $_flags = array(); + + /** + * The list of user flags. + * + * @var array + */ + protected $_userflags = array(); + + /** + * Constructor. + */ + public function __construct() + { + /* Build list of default flags. */ + foreach (array('Imap', 'System') as $type) { + $di = new DirectoryIterator(IMP_BASE . '/lib/Flag/' . $type); + foreach ($di as $val) { + if ($val->isFile()) { + $cname = 'IMP_Flag_' . $type . '_' . $val->getBasename('.php'); + if (class_exists($cname)) { + $ob = new $cname(); + $this->_flags[$ob->id] = $ob; + } + } + } + } + + if ($f_list = $GLOBALS['prefs']->getValue('msgflags')) { + $f_list = @unserialize($f_list); + if (is_array($f_list)) { + foreach ($f_list as $val) { + $this->_userflags[$val->id] = $val; + } + } + } + + $this->changed = true; + } + + /** + * Save the flag list to the prefs backend. + */ + protected function _save() + { + global $prefs; + + if (!$prefs->isLocked('msgflags')) { + $prefs->setValue('msgflags', serialize($this->_userflags)); + } + + $this->changed = true; + } + + /** + * Return the raw list of flags. + * + * @param array $opts Additional options: + *
+     * 'imap' - (boolean) If true, only return IMAP flags that can be set by
+     *          the user.
+     *          DEFAULT: false
+     * 'mailbox' - (string) A real (not virtual) IMAP mailbox. If set, will
+     *             determine what flags are available in the mailbox.
+     *             DEFAULT: '' (no mailbox check)
+     * 
+ * + * @return array An array of IMP_Flag_Base elements. + */ + public function getList(array $opts = array()) + { + $ret = array_merge($this->_flags, $this->_userflags); + + if (!empty($opts['imap'])) { + foreach ($ret as $key => $val) { + if (!($val instanceof IMP_Flag_Imap)) { + unset($ret[$key]); + } + } + } + + if (!isset($opts['mailbox']) || !strlen($opts['mailbox'])) { + return array_values($ret); + } + + /* Alter the list of flags for a mailbox depending on the return + * from the PERMANENTFLAGS IMAP response. */ + try { + /* Make sure we are in R/W mailbox mode (SELECT). No flags are + * allowed in EXAMINE mode. */ + $imp_imap = $GLOBALS['injector']->getInstance('IMP_Injector_Factory_Imap')->create(); + $imp_imap->openMailbox($opts['mailbox'], Horde_Imap_Client::OPEN_READWRITE); + $status = $imp_imap->status($opts['mailbox'], Horde_Imap_Client::STATUS_PERMFLAGS); + } catch (Horde_Imap_Client_Exception $e) { + return array_values($ret); + } + + /* Limited flags allowed in mailbox. */ + if (array_search('\\*', $status['permflags']) === false) { + foreach ($ret as $key => $val) { + if (($val instanceof IMP_Flag_Imap) && + !in_array($val->imapflag, $status['permflags'])) { + unset($ret[$key]); + } + } + } + + /* Get list of unknown flags. */ + if ($GLOBALS['prefs']->getValue('show_all_flags')) { + /* Get list of IMAP flags. */ + $imapflags = array(); + foreach ($ret as $val) { + if ($val instanceof IMP_Flag_Imap) { + $imapflags[] = $val->imapflag; + } + } + + foreach ($status['permflags'] as $val) { + if (($val != '\\*') && !in_array($val, $imapflags)) { + $ob = new IMP_Flag_User(Horde_String::convertCharset($val, 'UTF7-IMAP', 'UTF-8'), $val); + $ret[] = $ob; + } + } + } + + return array_values($ret); + } + + /** + * Add a user-defined IMAP flag. + * + * @param string $label The label to use for the new flag. + * + * @return string The IMAP flag name. + */ + public function addFlag($label) + { + if (strlen($label) == 0) { + return; + } + + $ob = new IMP_Flag_User($label); + + if (!isset($this->_userflags[$ob->id])) { + $this->_userflags[$ob->id] = $ob; + $this->_save(); + } + + return $ob->imapflag; + } + + /** + * Updates flag properties. + * + * @param string $key The flag key. + * @param string $type The property to update. Either 'bgcolor' or + * 'label'. + * @param string $data The updated data. + */ + public function updateFlag($key, $type, $data) + { + if (isset($this->_flags[$key])) { + $ob = $this->_flags[$key]; + } elseif (isset($this->_userflags[$key])) { + $ob = $this->_userflags[$key]; + } else { + return; + } + + $ob->$type = $data; + + if (isset($this->_flags[$key]) && ($this->_flags[$key] == $ob)) { + if (isset($this->_userflags[$key])) { + unset($this->_userflags[$key]); + $this->_save(); + } + } else { + $this->_userflags[$key] = $ob; + $this->_save(); + } + } + + /** + * Parse a list of flag information. + * + * @param array $opts Options: + *
+     * 'flags' - (array) IMAP flag info. A lowercase list of flags returned
+     *           by the IMAP server.
+     * 'headers' - (Horde_Mime_Headers) Determines attachment and priority
+     *             information from a headers object.
+     * 'personal' - (mixed) Personal message info. Either an array of To
+     *              addresses as returned by
+     *              Horde_Mime_Address::getAddressesFromObject() or the
+     *              identity that matched the address list.
+     * 
+ * + * @return array A list of IMP_Flag_Base objects. + */ + public function parse(array $opts = array()) + { + $opts = array_merge(array( + 'flags' => array(), + 'headers' => null, + 'personal' => null + ), $opts); + + $imap = ($GLOBALS['session']->get('imp', 'protocol') == 'imap'); + $ret = array(); + + foreach (array_merge($this->_flags, $this->_userflags) as $val) { + switch (get_class($val)) { + case 'IMP_Flag_System_Attachment': + case 'IMP_Flag_System_Encrypted': + case 'IMP_Flag_System_HighPriority': + case 'IMP_Flag_System_LowPriority': + case 'IMP_Flag_System_Signed': + if (!is_null($opts['headers']) && + $val->match($opts['headers'])) { + $ret[] = $val; + } + break; + + case 'IMP_Flag_System_Personal': + if (!is_null($opts['personal']) && + $val->match($opts['personal'])) { + $ret[] = $val; + } + break; + + case 'IMP_Flag_System_Unseen': + default: + if ($imap && $val->match($opts['flags'])) { + $ret[] = $val; + } + break; + } + } + + return $ret; + } + + /** + * Process a flag ID formatted for use in form data. + * + * @param string $id The ID from form data. + * + * @return array Two element array: + *
+     * 'flag' - (string) The flag name.
+     * 'set' - (boolean) Whether the flag should be set or not.
+     * 
+ */ + public function parseFormId($id) + { + return (strpos($id, '0\\') === 0) + ? array('flag' => substr($id, 2), 'set' => false) + : array('flag' => $id, 'set' => true); + } + + /** + * Returns a list of flags that have changed due to IMAP flag changes. + * + * @param array $flags The list of IMAP flags added/removed. + * @param boolean $add True if these flags were added, false if they were + * removed. + * + * @return array Array with two keys: 'add' and 'remove'. Each key + * contains a list of IMP_Flag_Base objects. + */ + public function changed($flags, $add) + { + $ret = array( + 'add' => array(), + 'remove' => array() + ); + + $obs = array(); + foreach ($flags as $val) { + $obs[] = $this[$val]; + } + + if ($add) { + $ret['add'] = $obs; + } else { + $ret['remove'] = $obs; + } + + foreach (array_merge($this->_flags, $this->_userflags) as $val) { + $res = $val->changed($obs, $add); + + if ($res === false) { + $ret['remove'][] = $val; + } elseif ($res === true) { + $ret['add'][] = $val; + } + } + + return $ret; + } + + /* ArrayAccess methods. */ + + /** + */ + public function offsetExists($offset) + { + return isset($this->_flags[$offset]) || + isset($this->_userflags[$offset]); + } + + /** + */ + public function offsetGet($offset) + { + if (isset($this->_flags[$offset])) { + return $this->_flags[$offset]; + } elseif ($this->_userflags[$offset]) { + return $this->_userflags[$offset]; + } + + return null; + } + + /** + * @throws InvalidArgumentException + */ + public function offsetSet($offset, $value) + { + throw new InvalidArgumentException('Use addFlag()/updateFlag()'); + } + + /** + */ + public function offsetUnset($offset) + { + if (isset($this->_userflags[$offset])) { + unset($this->_userflags[$offset]); + $this->_save(); + } + } + + /* Serializable methods. */ + + /** + */ + public function serialize() + { + return serialize(array( + $this->_flags, + $this->_userflags + )); + } + + /** + */ + public function unserialize($data) + { + $data = @unserialize($data); + if (!is_array($data)) { + throw new Exception('Cache invalidation.'); + } + + $this->_flags = $data[0]; + $this->_userflags = $data[1]; + } + +} diff --git a/imp/lib/Imap/Flags.php b/imp/lib/Imap/Flags.php deleted file mode 100644 index 80784c413..000000000 --- a/imp/lib/Imap/Flags.php +++ /dev/null @@ -1,484 +0,0 @@ - - * @category Horde - * @license http://www.fsf.org/copyleft/gpl.html GPL - * @package IMP - */ -class IMP_Imap_Flags -{ - /** - * The cached list of flags. - * - * @var array - */ - protected $_flags = null; - - /** - * The 'msgflags_user' preference value. - * - * @var array - */ - protected $_userflags = null; - - /** - * Temporary flags (i.e. flags created by other MUAs). - * - * @var array - */ - protected $_tempflags = array(); - - /** - * Save the flag list to the prefs backend. - * - * @param boolean $user If true, update the user flag list. Otherwise, - * update the system flag list. - */ - protected function _save($user = true) - { - global $prefs; - - if ($user) { - if (!$prefs->isLocked('msgflags_user')) { - $prefs->setValue('msgflags_user', json_encode($this->_userflags)); - } - } elseif (!$prefs->isLocked('msgflags')) { - $prefs->setValue('msgflags', json_encode(array_diff_key($this->_flags, $this->_userflags))); - } - } - - /** - * Return the raw list of flags. - * - * @param array $options Additional options: - *
-     * 'div' - (boolean) If true, return a DIV tag containing the code
-     *         necessary to display the icon.
-     *         DEFAULT: false
-     * 'fgcolor' - (boolean) If true, add foreground color information to be
-     *             used for text overlay purposes.
-     *             DEFAULT: false
-     * 'imap' - (boolean) If true, only return IMAP flags that can be set by
-     *          the user.
-     *          DEFAULT: false
-     * 'mailbox' - (string) A real (not virtual) IMAP mailbox. If set, will
-     *             determine what flags are available in the mailbox.
-     *             DEFAULT: '' (no mailbox check)
-     * 
- * - * @return array An array of flag information (see 'msgflags' preference - * for format). If 'fgcolor' option is true, also adds - * a 'f' key to each entry with foreground color info. - * If 'div' option is true, adds a 'div' key with HTML - * text. - */ - public function getList($options = array()) - { - $this->_loadList(); - - $avail_flags = array_keys($this->_flags); - - $ret = $types = array(); - if (!empty($options['imap'])) { - $types = array('imapp', 'imapu'); - } - - /* Reduce the list of flags for the mailbox depending on the return - * from the PERMANENTFLAGS IMAP response. */ - if (!empty($options['mailbox'])) { - try { - /* Make sure we are in R/W mailbox mode (SELECT). No flags are - * allowed in EXAMINE mode. */ - $imp_imap = $GLOBALS['injector']->getInstance('IMP_Injector_Factory_Imap')->create(); - $imp_imap->openMailbox($options['mailbox'], Horde_Imap_Client::OPEN_READWRITE); - $status = $imp_imap->status($options['mailbox'], Horde_Imap_Client::STATUS_PERMFLAGS); - - if (($pos = array_search('\\*', $status['permflags'])) !== false) { - if ($GLOBALS['prefs']->getValue('show_all_flags')) { - unset($status['permflags'][$pos]); - $avail_flags = array_keys(array_flip(array_merge($avail_flags, $status['permflags']))); - } - } else { - $avail_flags = $GLOBALS['prefs']->getValue('show_all_flags') - ? $status['permflags'] - : array_filter(array_diff($status['permflags'], $avail_flags)); - } - } catch (Horde_Imap_Client_Exception $e) {} - } - - foreach ($avail_flags as $key) { - if (!isset($this->_flags[$key])) { - /* Keywords might be UTF7-IMAP encoded. */ - $ret[$key] = $this->_createEntry(Horde_String::convertCharset($key, 'UTF7-IMAP', 'UTF-8')); - $ret[$key]['flag'] = $key; - $this->_tempflags[$key] = $ret[$key]; - } else { - $ret[$key] = $this->_flags[$key]; - if (!empty($options['imap']) && - !in_array($ret[$key]['t'], $types)) { - unset($ret[$key]); - } else { - $ret[$key]['flag'] = $key; - if (!empty($options['fgcolor'])) { - $ret[$key] = $this->_getColor($key, $ret[$key]); - } - if (!empty($options['div']) && isset($ret[$key]['c'])) { - $ret[$key]['div'] = $this->_getDiv($ret[$key]['c'], $ret[$key]['l']); - } - } - } - } - - return $ret; - } - - /** - * Loads the flag list from the preferences into the local cache. - */ - protected function _loadList() - { - if (!is_null($this->_flags)) { - return; - } - - $this->_userflags = json_decode($GLOBALS['prefs']->getValue('msgflags_user'), true); - $this->_flags = array_merge( - $this->_userflags, - json_decode($GLOBALS['prefs']->getValue('msgflags'), true) - ); - - /* Sanity checking. */ - if (is_array($this->_flags)) { - $this->_flags = array_change_key_case($this->_flags, CASE_LOWER); - } else { - $this->_flags = array(); - $this->_save(); - } - } - - /** - * Add a user-defined IMAP flag. - * - * @param string $label The label to use for the new flag. - * - * @return string The IMAP flag name. - */ - public function addFlag($label) - { - if (strlen($label) == 0) { - return; - } - - $this->_loadList(); - - /* IMAP keywords must conform to RFC 3501 [9] (flag-keyword). Convert - * whitespace to underscore. */ - $key = $GLOBALS['injector']->getInstance('IMP_Injector_Factory_Imap')->create()->getUtils()->stripNonAtomChars(Horde_String::convertCharset(strtr($label, ' ', '_'), 'UTF-8', 'UTF7-IMAP')); - if (!isset($this->_flags[$key])) { - $entry = $this->_createEntry($label); - - $this->_flags[$key] = $entry; - $this->_userflags[$key] = $entry; - - $this->_save(); - } - - return $key; - } - - /** - * Creates a flag entry data object. - * - * @param string $label The label to use for the flag. - * - * @return array Flag data object. - */ - protected function _createEntry($label) - { - return array( - // 'a' => These flags are not shown in mimp - 'b' => $GLOBALS['prefs']->getValue('msgflags_color'), - 'c' => 'flagUser', - 'd' => true, - 'l' => $label, - 't' => 'imapp' - ); - } - - /** - * Updates a flag. - * - * @param string $label The flag label. - * @param array $data The data to update. - */ - public function updateFlag($label, $data) - { - $this->_loadList(); - - if (isset($this->_flags[$label])) { - foreach ($data as $key => $val) { - $this->_flags[$label][$key] = $val; - } - - $this->_save(isset($this->_updateflags[$label])); - } - } - - /** - * Delete a flag from the list. - * - * @param string $label The flag label. - * - * @return boolean True on success. - */ - public function deleteFlag($label) - { - $this->_loadList(); - - if (isset($this->_flags[$label]) && - $this->_flags[$label]['l'] && - !empty($this->_flags[$label]['d'])) { - $user_flag = isset($this->_userflags[$label]); - unset($this->_flags[$label], $this->_userflags[$label]); - $this->_save($user_flag); - return true; - } - - return false; - } - - /** - * Parse a list of flag information. - * - * @param array $options Additional options: - *
-     * 'div' - (boolean) If true, return a DIV tag containing the code
-     *         necessary to display the icon.
-     *         DEFAULT: false
-     * 'flags' - (array) [REQUIRED] IMAP flag info. A lowercase list of flags
-     *           returned by the IMAP server.
-     * 'headers' - (Horde_Mime_Headers) Determines attachment and priority
-     *             information from a headers object.
-     * 'personal' - (mixed) Personal message info. Either an array of to
-     *              addresses as returned by
-     *              Horde_Mime_Address::getAddressesFromObject(), or the
-     *              identity that matched the address list.
-     * 
- * - * @return array A list of flags with the following keys: - *
-     * 'abbrev' - (string) The abbreviation to use.
-     * 'bg' - (string) The background to use.
-     * 'classname' - (string) If set, the flag classname to use.
-     * 'fg' - (string) The foreground color to use.
-     * 'flag' - (string) The matched flag (lowercase).
-     * 'div' - (string) A DIV HTML element, if 'div' option is true and a
-     *         classname is defined.
-     * 'label' - (string) The label of the flag.
-     * 'type' - (string) The flag type.
-     * 
- */ - public function parse($options = array()) - { - $this->_loadList(); - - $process = $ret = array(); - $f = $this->_flags; - - if (isset($options['personal'])) { - if (is_array($options['personal'])) { - $identity = $GLOBALS['injector']->getInstance('IMP_Identity'); - foreach ($options['personal'] as $val) { - if ($identity->hasAddress($val['inner'])) { - $process['personal'] = $f['personal']; - break; - } - } - } else if (!is_null($options['personal'])) { - $process['personal'] = $f['personal']; - } - } - - if (!empty($options['headers'])) { - $imp_hdr_ui = new IMP_Ui_Headers(); - switch ($imp_hdr_ui->getPriority($options['headers'])) { - case 'high': - $process['highpri'] = $f['highpri']; - break; - - case 'low': - $process['lowpri'] = $f['lowpri']; - break; - } - - if ($ctype = $options['headers']->getValue('content-type', Horde_Mime_Headers::VALUE_BASE)) { - $imp_mbox_ui = new IMP_Ui_Mailbox(); - if ($type = $imp_mbox_ui->getAttachmentType($ctype)) { - $process[$type] = $f[$type]; - } - } - } - - if ($GLOBALS['session']->get('imp', 'protocol') == 'imap') { - $flaglist = empty($options['flags']) - ? array() - : array_map('strtolower', $options['flags']); - - foreach (array_merge($f, $this->_tempflags) as $k => $v) { - if (in_array($v['t'], array('imap', 'imapp', 'imapu', 'imp'))) { - $match = in_array($k, $flaglist); - if (!empty($v['n'])) { - $match = !$match; - } - - if ($match) { - $process[$k] = $v; - } - } - } - } - - foreach ($process as $key => $val) { - $color = $this->_getColor($key, $val); - - $tmp = array( - 'bg' => $color['b'], - 'fg' => $color['f'], - 'flag' => $key, - 'label' => $val['l'], - 'type' => $val['t'] - ); - - if (isset($val['a'])) { - $tmp['abbrev'] = $val['a']; - } - - if (isset($val['c'])) { - $tmp['classname'] = $val['c']; - if (!empty($options['div'])) { - $tmp['div'] = $this->_getDiv($val['c'], $val['l']); - } - } - - $ret[] = $tmp; - } - - return $ret; - } - - /** - * Get the list of set/unset actions for use in dropdown lists. - * - * @param string $mbox The current mailbox. - * - * @return array An array with 2 elements: 'set' and 'unset'. - */ - public function getFlagList($mbox) - { - $ret = array('set' => array(), 'unset' => array()); - - foreach ($this->getList(array('imap' => true, 'mailbox' => $mbox)) as $val) { - $tmp = array( - 'f' => $val['flag'], - 'l' => $val['l'] - ); - - /* Check for 'opposite' flag actions. */ - $act1 = isset($val['n']) ? 'unset' : 'set'; - $act2 = ($act1 == 'set') ? 'unset' : 'set'; - - $ret[$act1][] = $tmp; - $tmp['f'] = '0\\' . $val['flag']; - $ret[$act2][] = $tmp; - } - - return $ret; - } - - /** - * Output a DIV element to display the icon. - * - * @param string $c A classname. - * @param string $l The flag label. - * - * @return string A HTML DIV element. - */ - protected function _getDiv($c, $l) - { - return '
'; - } - - /** - * Process a flag ID formatted for use in form data. - * - * @param string $id The ID from form data. - * - * @return array Two element array: - *
-     * 'flag' - (string) The flag name.
-     * 'set' - (boolean) Whether the flag should be set or not.
-     * 
- */ - public function parseFormId($id) - { - if (strpos($id, '0\\') === 0) { - return array('flag' => substr($id, 2), 'set' => false); - } - return array('flag' => $id, 'set' => true); - } - - /** - * Given a flag/set combo, returns the text label. - * - * @param string $name Flag name. - * @param boolean $set Search for set flag? - * - * @return string The text label. - */ - public function getLabel($name, $set) - { - $flist = $this->getList(); - - if (!isset($flist[$name])) { - return ''; - } - - if (!empty($flist[$name]['n'])) { - $set = !$set; - } - - return $set - ? $flist[$name]['l'] - : sprintf(_("Not %s"), $flist[$name]['l']); - } - - /** - * Determines the colors for an entry. - * - * @param string $key The flag key. - * @param array $in The array of flag data. - * - * @return array $in with the 'b' and 'f' keys populated. - */ - protected function _getColor($key, $in) - { - $in['f'] = '#000'; - - if (!isset($in['b'])) { - $in['b'] = '#fff'; - } elseif (Horde_Image::brightness($in['b']) < 128) { - $in['f'] = '#f6f6f6'; - } - - return $in; - } - -} diff --git a/imp/lib/Indices.php b/imp/lib/Indices.php index 9179c81e8..f24a12f5d 100644 --- a/imp/lib/Indices.php +++ b/imp/lib/Indices.php @@ -132,14 +132,33 @@ class IMP_Indices implements Countable, Iterator /** * Returns mailbox/UID information for the first index. * - * @return array A 2-element array with the mailbox and the UID. + * @return boolean $all If true, returns all UIDs for the first index + * in an array. If false, returns the first UID for + * the first index as a string. + * + * @return array A 2-element array with the mailbox and the UID(s). */ - public function getSingle() + public function getSingle($all = false) { $val = reset($this->_indices); - return array(key($this->_indices), reset($val)); + return array(key($this->_indices), $all ? $val : reset($val)); + } + + /** + * Return a copy of the indices array. + * + * @return array The indices array (keys are mailbox names, values are + * arrays of UIDS). + */ + public function indices() + { + /* This creates a copy of the indices array. Needed because the + * Iterator functions rely on pointers. */ + return $this->_indices; } + /* Countable methods. */ + /** * Index count. * @@ -156,19 +175,6 @@ class IMP_Indices implements Countable, Iterator return $count; } - /** - * Return a copy of the indices array. - * - * @return array The indices array (keys are mailbox names, values are - * arrays of UIDS). - */ - public function indices() - { - /* This creates a copy of the indices array. Needed because the - * Iterator functions rely on pointers. */ - return $this->_indices; - } - /* Magic methods. */ /** diff --git a/imp/lib/Injector/Factory/Flags.php b/imp/lib/Injector/Factory/Flags.php new file mode 100644 index 000000000..f4f255ebf --- /dev/null +++ b/imp/lib/Injector/Factory/Flags.php @@ -0,0 +1,66 @@ + + * @category Horde + * @license http://www.fsf.org/copyleft/gpl.html GPL + * @link http://pear.horde.org/index.php?package=IMP + * @package IMP + */ + +/** + * A Horde_Injector based factory for the IMP_Flags object. + * + * Copyright 2010 The Horde Project (http://www.horde.org/) + * + * See the enclosed file COPYING for license information (GPL). If you + * did not receive this file, see http://www.fsf.org/copyleft/gpl.html. + * + * @author Michael Slusarz + * @category Horde + * @license http://www.fsf.org/copyleft/gpl.html GPL + * @link http://pear.horde.org/index.php?package=IMP + * @package IMP + */ +class IMP_Injector_Factory_Flags +{ + /** + * Return the IMP_Flags instance. + * + * @return IMP_Flags The singleton instance. + */ + public function create(Horde_Injector $injector) + { + try { + $instance = $GLOBALS['session']->get('imp', 'flags'); + } catch (Exception $e) { + Horde::logMessage('Could not unserialize stored IMP_Flags object.', 'DEBUG'); + $instance = null; + } + + if (is_null($instance)) { + $instance = new IMP_Flags(); + } + + register_shutdown_function(array($this, 'shutdown'), $instance); + + return $instance; + } + + /** + * Store serialized version of object in the current session. + * + * @param IMP_Flags $instance Flags object. + */ + public function shutdown($instance) + { + /* Only need to store the object if the object has changed. */ + if ($instance->changed) { + $GLOBALS['session']->set('imp', 'flags', $instance); + } + } + +} diff --git a/imp/lib/Message.php b/imp/lib/Message.php index 6a3930a4a..0f359b3cb 100644 --- a/imp/lib/Message.php +++ b/imp/lib/Message.php @@ -651,12 +651,12 @@ class IMP_Message } /** - * Sets or clears a given flag(s) for all messages in a list of mailboxes. + * Adds or removes flag(s) for all messages in a list of mailboxes. * This function works with IMAP only, not POP3. * - * @param array $flags The IMAP flag(s) to set or clear. + * @param array $flags The IMAP flag(s) to add or remove. * @param array $mboxes The list of mailboxes to flag. - * @param boolean $action If true, set the flag(s), otherwise, clear the + * @param boolean $action If true, add the flag(s), otherwise, remove the * flag(s). * * @return boolean True if successful, false if not. diff --git a/imp/lib/Prefs/Ui.php b/imp/lib/Prefs/Ui.php index fab6e01c1..9ab665cdd 100644 --- a/imp/lib/Prefs/Ui.php +++ b/imp/lib/Prefs/Ui.php @@ -471,8 +471,7 @@ class IMP_Prefs_Ui return $prefs->setValue('default_encrypt', $ui->vars->default_encrypt); case 'flagmanagement': - $this->_updateFlagManagement($ui); - return false; + return $this->_updateFlagManagement($ui); case 'initialpageselect': return $prefs->setValue('initial_page', IMP::formMbox($ui->vars->initial_page, false)); @@ -935,49 +934,38 @@ class IMP_Prefs_Ui 'ImpFlagPrefs.confirm_delete' => _("Are you sure you want to delete this flag?") )); - $msgflags_locked = $GLOBALS['prefs']->isLocked('msgflags'); - $userflags_locked = $GLOBALS['prefs']->isLocked('msgflags_user'); - $t = $GLOBALS['injector']->createInstance('Horde_Template'); $t->setOption('gettext', true); + $t->set('locked', $GLOBALS['prefs']->isLocked('msgflags')); $out = array(); - $flaglist = $GLOBALS['injector']->getInstance('IMP_Imap_Flags')->getList(array('div' => true, 'fgcolor' => true)); - foreach ($flaglist as $key => $val) { - $hash = hash('md5', $key); + $flaglist = $GLOBALS['injector']->getInstance('IMP_Flags')->getList(); + foreach ($flaglist as $val) { + $hash = hash('md5', $val->id); $bgid = 'bg_' . $hash; - $color = htmlspecialchars($val['b']); - $label = htmlspecialchars($val['l']); + $color = htmlspecialchars($val->bgcolor); + $label = htmlspecialchars($val->label); $bgstyle = 'background-color:' . $color; $tmp = array(); - if ($val['t'] == 'imapp') { + if ($val instanceof IMP_Flag_User) { $tmp['label'] = $label; - $tmp['imapp'] = true; + $tmp['user'] = true; $tmp['label_name'] = 'label_' . $hash; - if ($userflags_locked) { - $tmp['locked'] = true; - } } else { $tmp['label'] = Horde::label($bgid, $label); - $tmp['icon'] = $val['div']; - if ($msgflags_locked) { - $tmp['locked'] = true; - } + $tmp['icon'] = $val->div; } - $tmp['colorstyle'] = $bgstyle . ';color:' . htmlspecialchars($val['f']); + $tmp['colorstyle'] = $bgstyle . ';color:' . htmlspecialchars($val->fgcolor); $tmp['colorid'] = $bgid; $tmp['color'] = $color; - $tmp['flag_del'] = !empty($val['d']); - $out[] = $tmp; } $t->set('flags', $out); $t->set('picker_img', Horde::img('colorpicker.png', _("Color Picker"))); - $t->set('userflags_notlocked', !$userflags_locked); return $t->fetch(IMP_TEMPLATES . '/prefs/flags.html'); } @@ -986,10 +974,12 @@ class IMP_Prefs_Ui * Update IMAP flag related preferences. * * @param Horde_Core_Prefs_Ui $ui The UI object. + * + * @return boolean True if preferences were updated. */ protected function _updateFlagManagement($ui) { - $imp_flags = $GLOBALS['injector']->getInstance('IMP_Imap_Flags'); + $imp_flags = $GLOBALS['injector']->getInstance('IMP_Flags'); if ($ui->vars->flag_action == 'add') { $GLOBALS['notification']->push(sprintf(_("Added flag \"%s\"."), $ui->vars->flag_data), 'horde.success'); @@ -997,38 +987,41 @@ class IMP_Prefs_Ui return; } - $def_color = $GLOBALS['prefs']->getValue('msgflags_color'); - - // Don't set updated on these actions. User may want to do more actions. - foreach ($imp_flags->getList() as $key => $val) { - $md5 = hash('md5', $key); + // Don't set updated on these actions. User may want to do more + // actions. + $update = false; + foreach ($imp_flags->getList() as $val) { + $md5 = hash('md5', $val->id); switch ($ui->vars->flag_action) { case 'delete': - if (($ui->vars->flag_data == ('bg_' . $md5)) && - $imp_flags->deleteFlag($key)) { - $GLOBALS['notification']->push(sprintf(_("Deleted flag \"%s\"."), $val['l']), 'horde.success'); + if ($ui->vars->flag_data == ('bg_' . $md5)) { + unset($imp_flags[$val->id]); + $GLOBALS['notification']->push(sprintf(_("Deleted flag \"%s\"."), $val->label), 'horde.success'); } break; default: /* Change labels for user-defined flags. */ - if ($val['t'] == 'imapp') { + if ($val instanceof IMP_Flag_User) { $label = $ui->vars->get('label_' . $md5); - if (strlen($label) && ($label != $val['l'])) { - $imp_flags->updateFlag($key, array('l' => $label)); + if (strlen($label) && ($label != $val->label)) { + $imp_flags->updateFlag($val->id, 'label', $label); + $update = true; } } /* Change background for all flags. */ $bg = strtolower($ui->vars->get('bg_' . $md5)); - if ((isset($val['b']) && ($bg != $val['b'])) || - (!isset($val['b']) && ($bg != $def_color))) { - $imp_flags->updateFlag($key, array('b' => $bg)); + if ($bg != $val->bgcolor) { + $imp_flags->updateFlag($val->id, 'bgcolor', $bg); + $update = true; } break; } } + + return $update; } /* Initial page selection. */ diff --git a/imp/lib/Search/Element/Flag.php b/imp/lib/Search/Element/Flag.php index 3d102fa6e..8f5aeef07 100644 --- a/imp/lib/Search/Element/Flag.php +++ b/imp/lib/Search/Element/Flag.php @@ -52,7 +52,8 @@ class IMP_Search_Element_Flag extends IMP_Search_Element */ public function queryText() { - return sprintf(_("flagged \"%s\""), $GLOBALS['injector']->getInstance('IMP_Imap_Flags')->getLabel($this->_data->f, $this->_data->s)); + $imp_flags = $GLOBALS['injector']->getInstance('IMP_Flags'); + return sprintf(_("flagged \"%s\""), $imp_flags[$this->_data->f]->getLabel($this->_data->s)); } } diff --git a/imp/lib/Ui/Mailbox.php b/imp/lib/Ui/Mailbox.php index 4d2ec80e7..7f5955998 100644 --- a/imp/lib/Ui/Mailbox.php +++ b/imp/lib/Ui/Mailbox.php @@ -157,38 +157,6 @@ class IMP_Ui_Mailbox } /** - * Return the icon to use for a given attachment. - * - * @return string The mailbox display icon type (attach, encrypt, - * signed). - */ - public function getAttachmentType($type) - { - list($primary, $sub) = explode('/', $type, 2); - if ($primary == 'multipart') { - switch ($sub) { - case 'signed': - return 'signed'; - - case 'encrypted': - return 'encrypt'; - - case 'alternative': - case 'related': - /* Treat this as no attachments. */ - break; - - default: - return 'attach'; - } - } elseif ($type == 'application/pkcs7-mime') { - return 'encrypt'; - } - - return ''; - } - - /** * Formats the date header. * * @param integer $date The UNIX timestamp. diff --git a/imp/lib/Views/ListMessages.php b/imp/lib/Views/ListMessages.php index 2ade2e72a..71db09491 100644 --- a/imp/lib/Views/ListMessages.php +++ b/imp/lib/Views/ListMessages.php @@ -148,7 +148,15 @@ class IMP_Views_ListMessages } /* Generate flag array. */ - $md->flags = array_keys($GLOBALS['injector']->getInstance('IMP_Imap_Flags')->getList(array('imap' => true, 'mailbox' => $is_search ? null : $mbox))); + $flaglist = $GLOBALS['injector']->getInstance('IMP_Flags')->getList(array( + 'imap' => true, + 'mailbox' => $is_search ? null : $mbox + )); + + $md->flags = array(); + foreach ($flaglist as $val) { + $md->flags[] = $val->imapflag; + } } /* The search query may have changed. */ @@ -423,7 +431,7 @@ class IMP_Views_ListMessages } } - $flag_parse = $GLOBALS['injector']->getInstance('IMP_Imap_Flags')->parse(array( + $flag_parse = $GLOBALS['injector']->getInstance('IMP_Flags')->parse(array( 'flags' => $ob['flags'], 'headers' => $ob['headers'], 'personal' => Horde_Mime_Address::getAddressesFromObject($ob['envelope']['to'], array('charset' => $charset)) @@ -432,7 +440,7 @@ class IMP_Views_ListMessages if (!empty($flag_parse)) { $msg['flag'] = array(); foreach ($flag_parse as $val) { - $msg['flag'][] = $val['flag']; + $msg['flag'][] = $val->id; } } diff --git a/imp/lib/Views/ShowMessage.php b/imp/lib/Views/ShowMessage.php index bfe945eed..3a4d31bef 100644 --- a/imp/lib/Views/ShowMessage.php +++ b/imp/lib/Views/ShowMessage.php @@ -108,27 +108,21 @@ class IMP_Views_ShowMessage /* Get envelope/header information. We don't use flags in this * view. */ + $imp_contents = null; try { $fetch_ret = $GLOBALS['injector']->getInstance('IMP_Injector_Factory_Imap')->create()->fetch($mailbox, array( Horde_Imap_Client::FETCH_ENVELOPE => true, Horde_Imap_Client::FETCH_HEADERTEXT => array(array('parse' => true, 'peek' => false)) ), array('ids' => array($uid))); - } catch (Horde_Imap_Client_Exception $e) { - $result['error'] = $error_msg; - $result['errortype'] = 'horde.error'; - return $result; - } - if (!isset($fetch_ret[$uid]['headertext'])) { - $result['error'] = $error_msg; - $result['errortype'] = 'horde.error'; - return $result; - } + if (isset($fetch_ret[$uid]['headertext'])) { + /* Parse MIME info and create the body of the message. */ + $imp_contents = $GLOBALS['injector']->getInstance('IMP_Injector_Factory_Contents')->create(new IMP_Indices($mailbox, $uid)); + } + } catch (Horde_Imap_Client_Exception $e) { + } catch (IMP_Exception $e) {} - /* Parse MIME info and create the body of the message. */ - try { - $imp_contents = $GLOBALS['injector']->getInstance('IMP_Injector_Factory_Contents')->create(new IMP_Indices($mailbox, $uid)); - } catch (IMP_Exception $e) { + if (is_null($imp_contents)) { $result['error'] = $error_msg; $result['errortype'] = 'horde.error'; return $result; diff --git a/imp/mailbox-mimp.php b/imp/mailbox-mimp.php index d785ccded..24fb4fe41 100644 --- a/imp/mailbox-mimp.php +++ b/imp/mailbox-mimp.php @@ -176,17 +176,17 @@ while (list(,$ob) = each($mbox_info['overview'])) { $msg['from'] = Horde_String::truncate($getfrom['from'], 50); /* Get flag information. */ - $flag_parse = $injector->getInstance('IMP_Imap_Flags')->parse(array( + $flag_parse = $injector->getInstance('IMP_Flags')->parse(array( 'flags' => $ob['flags'], - 'personal' => Horde_Mime_Address::getAddressesFromObject($ob['envelope']['to'], array('charset' => 'UTF-8')), - 'priority' => $ob['headers'] + 'headers' => $ob['headers'], + 'personal' => Horde_Mime_Address::getAddressesFromObject($ob['envelope']['to'], array('charset' => 'UTF-8')) )); foreach ($flag_parse as $val) { - if (isset($val['abbrev'])) { - $msg['status'] .= $val['abbrev']; - } elseif ($val['type'] == 'imapp') { - $msg['subject'] = '*' . Horde_String::truncate($val['label'], 8) . '* ' . $msg['subject']; + if ($abbrev = $val->abbreviation) { + $msg['status'] .= $abbrev; + } elseif ($val instanceof IMP_Flag_User) { + $msg['subject'] = '*' . Horde_String::truncate($val->label, 8) . '* ' . $msg['subject']; } } diff --git a/imp/mailbox.php b/imp/mailbox.php index 883e91d65..8064450e5 100644 --- a/imp/mailbox.php +++ b/imp/mailbox.php @@ -64,7 +64,7 @@ if (!Horde_Util::nonInputVar('from_message_page')) { } $do_filter = false; -$imp_flags = $injector->getInstance('IMP_Imap_Flags'); +$imp_flags = $injector->getInstance('IMP_Flags'); $imp_imap = $injector->getInstance('IMP_Injector_Factory_Imap')->create(); $indices = new IMP_Indices($vars->indices); @@ -485,9 +485,25 @@ if ($pageOb['msgcount']) { $n_template->set('use_pop', $session->get('imp', 'protocol') == 'pop'); if (!$n_template->get('use_pop')) { - $tmp = $imp_flags->getFlagList($search_mbox ? null : IMP::$mailbox); - $n_template->set('flaglist_set', $tmp['set']); - $n_template->set('flaglist_unset', $tmp['unset']); + $args = array( + 'imap' => true, + 'mailbox' => $search_mbox ? null : IMP::$mailbox + ); + + $form_set = $form_unset = array(); + foreach ($imp_flags->getList($args) as $val) { + $form_set[] = array( + 'f' => $val->form_set, + 'l' => $val->label + ); + $form_unset[] = array( + 'f' => $val->form_unset, + 'l' => $val->label + ); + } + + $n_template->set('flaglist_set', $form_set); + $n_template->set('flaglist_unset', $form_unset); if (!$search_mbox) { $filters = array(); @@ -755,7 +771,6 @@ while (list(,$ob) = each($mbox_info['overview'])) { } catch (Horde_Exception_HookNotSet $e) {} $flag_parse = $imp_flags->parse(array( - 'div' => true, 'flags' => $ob['flags'], 'headers' => $ob['headers'], 'personal' => Horde_Mime_Address::getAddressesFromObject($ob['envelope']['to'], array('charset' => 'UTF-8')) @@ -763,16 +778,14 @@ while (list(,$ob) = each($mbox_info['overview'])) { $subject_flags = array(); foreach ($flag_parse as $val) { - if ($val['type'] == 'imapp') { + if ($val instanceof IMP_Flag_User) { $subject_flags[] = $val; } else { - if (isset($val['div'])) { - $msg['status'] .= $val['div']; - } - if (isset($val['classname'])) { - $msg['class'] = $val['classname']; + if (!$val->bgdefault) { + $msg['bg'] = $val->bgcolor; } - $msg['bg'] = $val['bg']; + $msg['class'] = $val->css; + $msg['status'] .= $val->div; } } @@ -830,9 +843,9 @@ while (list(,$ob) = each($mbox_info['overview'])) { /* Add subject flags. */ foreach ($subject_flags as $val) { - $flag_label = Horde_String::truncate($val['label'], 12); + $flag_label = Horde_String::truncate($val->label, 12); - $msg['subject'] = '' . htmlspecialchars($flag_label) . '' . $msg['subject']; + $msg['subject'] = '' . htmlspecialchars($flag_label) . '' . $msg['subject']; } /* Set up threading tree now. */ diff --git a/imp/message-dimp.php b/imp/message-dimp.php index aa275820d..2c3bf846d 100644 --- a/imp/message-dimp.php +++ b/imp/message-dimp.php @@ -29,7 +29,7 @@ switch ($vars->actionID) { case 'strip_attachment': try { $indices = $injector->getInstance('IMP_Message')->stripPart(new IMP_Indices($vars->folder, $vars->uid), $vars->id); - $js_vars['-DimpFullmessage.strip'] = 1; + $js_vars['-DimpMessage.strip'] = 1; list(,$vars->uid) = $indices->getSingle(); $notification->push(_("Attachment successfully stripped."), 'horde.success'); } catch (IMP_Exception $e) { @@ -58,15 +58,22 @@ if (isset($show_msg_result['error'])) { $scripts = array( array('contextsensitive.js', 'horde'), array('textarearesize.js', 'horde'), - array('fullmessage-dimp.js', 'imp'), + array('message-dimp.js', 'imp'), array('imp.js', 'imp'), ); foreach (array('from', 'to', 'cc', 'bcc', 'replyTo', 'log', 'uid', 'mailbox') as $val) { if (!empty($show_msg_result[$val])) { - $js_vars['DimpFullmessage.' . $val] = $show_msg_result[$val]; + $js_vars['DimpMessage.' . $val] = $show_msg_result[$val]; } } + +$js_vars['DimpMessage.flag'] = IMP_Ajax_Application::flagEntry(array('\\seen'), true, $vars->folder, $vars->uid); + +if ($poll = IMP_Ajax_Application::pollEntry($vars->folder)) { + $js_vars['DimpMessage.poll'] = $poll; +} + $js_out = Horde::addInlineJsVars($js_vars, array('ret_vars' => true)); /* Determine if compose mode is disabled. */ diff --git a/imp/message-mimp.php b/imp/message-mimp.php index 42abcf817..bc76cf6f1 100644 --- a/imp/message-mimp.php +++ b/imp/message-mimp.php @@ -217,20 +217,16 @@ if (!empty($msgAddresses)) { } } -$flag_parse = $injector->getInstance('IMP_Imap_Flags')->parse(array( +$flag_parse = $injector->getInstance('IMP_Flags')->parse(array( 'flags' => $flags, 'personal' => $match_identity )); foreach ($flag_parse as $val) { - if (isset($val['abbrev'])) { - $status .= $val['abbrev']; - } elseif ($val['type'] == 'imapp') { - if (Horde_String::length($val['label']) > 8) { - $status .= ' *' . Horde_String::substr($val['label'], 0, 5) . '...*'; - } else { - $status .= ' *' . $val['label'] . '*'; - } + if ($abbrev = $val->abbreviation) { + $status .= $abbrev; + } elseif ($val instanceof IMP_Flag_User) { + $status .= ' *' . Horde_String::truncate($val->label, 8) . '*'; } } diff --git a/imp/message.php b/imp/message.php index dbc7bc47c..4c0fcfc27 100644 --- a/imp/message.php +++ b/imp/message.php @@ -69,7 +69,7 @@ $mailbox_name = $index_array['mailbox']; $uid = $index_array['uid']; $indices = new IMP_Indices($mailbox_name, $uid); -$imp_flags = $injector->getInstance('IMP_Imap_Flags'); +$imp_flags = $injector->getInstance('IMP_Flags'); $imp_hdr_ui = new IMP_Ui_Headers(); $imp_ui = new IMP_Ui_Message(); @@ -409,17 +409,16 @@ if (is_null($identity)) { } $flag_parse = $imp_flags->parse(array( - 'div' => true, 'flags' => $flags, 'personal' => $match_identity )); $status = ''; foreach ($flag_parse as $val) { - if ($val['type'] == 'imapp') { - $status .= '' . htmlspecialchars($val['label']) . ''; + if ($val instanceof IMP_Flag_User) { + $status .= '' . htmlspecialchars($val->label) . ''; } else { - $status .= $val['div']; + $status .= $val->div; } } @@ -454,9 +453,25 @@ $n_template->set('id', 1); if (!$use_pop) { $n_template->set('mailbox', IMP::formMbox(IMP::$mailbox, true)); - $tmp = $imp_flags->getFlagList(IMP::$mailbox); - $n_template->set('flaglist_set', $tmp['set']); - $n_template->set('flaglist_unset', $tmp['unset']); + $tmp = $imp_flags->getList(array( + 'imap' => true, + 'mailbox' => IMP::$mailbox + )); + + $form_set = $form_unset = array(); + foreach ($tmp as $val) { + $form_set[] = array( + 'f' => $val->form_set, + 'l' => $val->label + ); + $form_unset[] = array( + 'f' => $val->form_unset, + 'l' => $val->label + ); + } + + $n_template->set('flaglist_set', $form_set); + $n_template->set('flaglist_unset', $form_unset); if ($conf['user']['allow_folders']) { $n_template->set('move', Horde::widget('#', _("Move to folder"), 'widget moveAction', '', '', _("Move"), true)); diff --git a/imp/package.xml b/imp/package.xml index 9896fd796..5e0796ec1 100644 --- a/imp/package.xml +++ b/imp/package.xml @@ -75,7 +75,7 @@ multiple folders, and multiple-language support. - + @@ -1141,7 +1141,7 @@ multiple folders, and multiple-language support. - + diff --git a/imp/search-basic.php b/imp/search-basic.php index 58ad0d422..a3b09dbbc 100644 --- a/imp/search-basic.php +++ b/imp/search-basic.php @@ -68,7 +68,7 @@ if ($vars->search_basic_mbox) { } if ($vars->search_criteria_flag) { - $formdata = $injector->getInstance('IMP_Imap_Flags')->parseFormId($vars->search_criteria_flag); + $formdata = $injector->getInstance('IMP_Flags')->parseFormId($vars->search_criteria_flag); $c_list[] = new IMP_Search_Element_Flag( $formdata['flag'], ($formdata['set'] && !$vars->search_criteria_flag_not) @@ -86,12 +86,15 @@ if ($vars->search_basic_mbox) { Horde::url('mailbox.php', true)->add('mailbox', strval($q_ob))->redirect(); } -$flist = $injector->getInstance('IMP_Imap_Flags')->getFlagList($vars->search_mailbox); +$flist = $injector->getInstance('IMP_Flags')->getList(array( + 'imap' => true, + 'mailbox' => $vars->search_mailbox +)); $flag_set = array(); -foreach ($flist['set'] as $val) { +foreach ($flist as $val) { $flag_set[] = array( - 'val' => $val['f'], - 'label' => $val['l'] + 'val' => $val->form_set, + 'label' => $val->label ); } diff --git a/imp/search.php b/imp/search.php index 5d6c50136..a492df951 100644 --- a/imp/search.php +++ b/imp/search.php @@ -148,7 +148,7 @@ if (!$browser->hasFeature('javascript') || exit; } -$imp_flags = $injector->getInstance('IMP_Imap_Flags'); +$imp_flags = $injector->getInstance('IMP_Flags'); $imp_search = $injector->getInstance('IMP_Search'); $vars = Horde_Variables::getDefaultVariables(); @@ -168,7 +168,10 @@ if (isset($vars->search_mailbox)) { $search_mailbox = array('INBOX'); } -$flist = $imp_flags->getFlagList($default_mailbox); +$flist = $imp_flags->getList(array( + 'imap' => true, + 'mailbox' => $default_mailbox +)); /* Generate the search query if 'criteria_form' is present in the form * data. */ @@ -433,12 +436,12 @@ $t->set('filterlist', $f_list); /* Create the flag list. */ $flag_set = array(); -foreach ($flist['set'] as $val) { +foreach ($flist as $val) { $flag_set[] = array( - 'val' => rawurlencode($val['f']), - 'label' => htmlspecialchars($val['l']) + 'val' => rawurlencode($val->form_set), + 'label' => htmlspecialchars($val->label) ); - $types[rawurlencode($val['f'])] = 'flag'; + $types[rawurlencode($val->form_set)] = 'flag'; } $t->set('flist', $flag_set); diff --git a/imp/templates/dimp/index.inc b/imp/templates/dimp/index.inc index d98661326..1c6d40992 100644 --- a/imp/templates/dimp/index.inc +++ b/imp/templates/dimp/index.inc @@ -437,6 +437,9 @@ function _simpleButton($id, $text, $image, $nodisplay = false) + +