kolab-webclient/dimp

Jeroen van Meeuwen vanmeeuwen at kolabsys.com
Tue Jan 11 00:58:52 CET 2011


 kolab-webclient/dimp/patches/dimp-1.1.6/0001-fix-broken-folder-images.patch    | 2197 +++++++++
 kolab-webclient/dimp/patches/dimp-1.1.6/0002-close-context-menu.patch          |   21 
 kolab-webclient/dimp/patches/dimp-1.1.6/0003-acl-view.patch                    |   83 
 kolab-webclient/dimp/patches/dimp-1.1.6/0004-folders-view.patch                |   41 
 kolab-webclient/dimp/patches/dimp-1.1.6/0005-itip-handling.patch               |   69 
 kolab-webclient/dimp/patches/dimp-1.1.6/0006-copy-msgs-with-ctrl.patch         |  629 ++
 kolab-webclient/dimp/patches/dimp-1.1.6/series                                 |   13 
 kolab-webclient/dimp/patches/dimp-1.1.6/t_dimp_HK_GW_ItipHandling.diff         |   72 
 kolab-webclient/dimp/patches/dimp-1.1.6/t_dimp_H_BL_CloseContextMenu.diff      |   45 
 kolab-webclient/dimp/patches/dimp-1.1.6/t_dimp_H_GW_AclView.diff               |  107 
 kolab-webclient/dimp/patches/dimp-1.1.6/t_dimp_H_GW_FoldersView.diff           |  100 
 kolab-webclient/dimp/patches/dimp-1.1.6/t_dimp_H_MS_CopyMessagesWithCtrl.diff  |  629 --
 kolab-webclient/dimp/patches/dimp-1.1.6/t_dimp_H_MS_FixBrokenFolderImages.diff | 2235 ----------
 13 files changed, 3047 insertions(+), 3194 deletions(-)

New commits:
commit dffe0f2c514be3c639f03641e35dfd138250a475
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date:   Mon Jan 10 23:58:21 2011 +0000

    Rebase patches onto the actual dimp-h3-1.1.6.tar.gz sources

diff --git a/kolab-webclient/dimp/patches/dimp-1.1.6/0001-fix-broken-folder-images.patch b/kolab-webclient/dimp/patches/dimp-1.1.6/0001-fix-broken-folder-images.patch
new file mode 100644
index 0000000..528468e
--- /dev/null
+++ b/kolab-webclient/dimp/patches/dimp-1.1.6/0001-fix-broken-folder-images.patch
@@ -0,0 +1,2197 @@
+diff -ur dimp-h3-1.1.6.orig/js/DimpBase.js dimp-h3-1.1.6/js/DimpBase.js
+--- dimp-h3-1.1.6.orig/js/DimpBase.js	2010-09-27 19:14:31.000000000 +0100
++++ dimp-h3-1.1.6/js/DimpBase.js	2011-01-10 23:49:33.895945000 +0000
+@@ -1 +1,2146 @@
+-var DimpBase={bcache:$H(),delay_onload:(!Prototype.Browser.Gecko&&!Prototype.Browser.Opera),lastrow:-1,mo_sidebar:$H(),pivotrow:-1,ppcache:$H(),ppfifo:[],showPreview:DIMP.conf.preview_pref,sfiltersfolder:$H({sf_all:"all",sf_current:"current"}),sfilters:$H({sf_msgall:"msgall",sf_from:"from",sf_to:"to",sf_subject:"subject"}),unseen_regex:new RegExp("(^|\\s)unseen(\\s|$)"),_select:function(c,a){var b=c.get("rownum");if(b.size()==1){this.lastrow=this.pivotrow=b.first()}this.toggleButtons();if($("previewPane").visible()){if(a.right){this.clearPreviewPane()}else{if(a.delay){(this.bcache.get("initPP")||this.bcache.set("initPP",this.initPreviewPane.bind(this))).delay(a.delay)}else{this.initPreviewPane()}}}},_deselect:function(d,b){var c=this.viewport.getSelected(),a=c.size();if(!a){this.lastrow=this.pivotrow=-1}this.toggleButtons();if(b.right||!a){this.clearPreviewPane()}else{if((a==1)&&$("previewPane").visible()){this._loadPreview(c.get("dataob").first())}}},msgSelect:function(g,c
 ){var b,e=this.viewport.createSelection("domid",g),a=e.get("rownum").first(),d=this.isSelected("domid",g),f=this.selectedCount();this.lastrow=a;$("msgList_filter").blur();if(c.shift){if(f){if(!d||f!=1){b=[a,this.pivotrow];this.viewport.select($A($R(b.min(),b.max())),{range:true})}return}}else{if(c.ctrl){this.pivotrow=a;if(d){this.viewport.deselect(e,{right:c.right});return}else{if(c.right||f){this.viewport.select(e,{add:true,right:c.right});return}}}}this.viewport.select(e,{right:c.right})},selectAll:function(){this.viewport.select($A($R(1,this.viewport.getMetaData("total_rows"))),{range:true})},isSelected:function(b,a){return this.viewport.getSelected().contains(b,a)},selectedCount:function(){return(this.viewport)?this.viewport.getSelected().size():0},resetSelected:function(){if(this.viewport){this.viewport.deselect(this.viewport.getSelected(),{clearall:true})}this.toggleButtons();this.clearPreviewPane()},moveSelected:function(a,g){var e,d,f,b,c;if(g){if(!this.viewport.getM
 etaData("total_rows")){return}e=a}else{if(a==0){return}c=thi!
 s.viewpo
rt.getSelected();switch(c.size()){case 0:e=this.viewport.currentOffset();e+=(a>0)?1:this.viewport.getPageSize("current");break;case 1:d=c.get("dataob").first();e=d.rownum+a;break;default:c=c.get("rownum");e=(a>0?c.max():c.min())+a;break}e=(a>0)?Math.min(e,this.viewport.getMetaData("total_rows")):Math.max(e,1)}f=this.viewport.createSelection("rownum",e);if(f.size()){b=f.get("dataob").first();if(!d||b.imapuid!=d.imapuid){this.viewport.scrollTo(b.rownum);this.viewport.select(f,{delay:0.3})}}else{this.offset=e;this.viewport.requestContentRefresh(e-1)}},go:function(e,b){var d,a,c;if(e.startsWith("compose:")){return}if(e.startsWith("msg:")){c=e.indexOf(":",4);a=e.substring(4,c);this.uid=e.substring(c+1);e="folder:"+a}if(e.startsWith("folder:")){a=e.substring(7);if(this.folder!=a||!$("dimpmain_folder").visible()){this.highlightSidebar(this.getFolderId(a));if(!$("dimpmain_folder").visible()){$("dimpmain_portal").hide();$("dimpmain_folder").show()}if(!Object.isUndefined(this.folder)){
 this._addHistory(e)}}this.loadFolder(a);return}this.folder=null;$("dimpmain_folder").hide();$("dimpmain_portal").update(DIMP.text.loading).show();if(e.startsWith("app:")){d=e.substr(4);if(d=="imp"||d=="dimp"){this.go("folder:INBOX");return}this.highlightSidebar("app"+d);this._addHistory(e,b);if(b){this.iframeContent(e,b)}else{if(DIMP.conf.app_urls[d]){this.iframeContent(e,DIMP.conf.app_urls[d])}}return}switch(e){case"portal":this.highlightSidebar("appportal");this._addHistory(e);DimpCore.setTitle(DIMP.text.portal);DimpCore.doAction("ShowPortal",{},[],this.bcache.get("portalC")||this.bcache.set("portalC",this._portalCallback.bind(this)));break;case"options":this.highlightSidebar("appoptions");this._addHistory(e);DimpCore.setTitle(DIMP.text.prefs);this.iframeContent(e,DIMP.conf.prefs_url);break}},_addHistory:function(b,a){if(Horde.dhtmlHistory.getCurrentLocation()!=b){Horde.dhtmlHistory.add(b,a)}},highlightSidebar:function(b){if($("foldersLoading").visible()){this.highlightSid
 ebar.bind(this,b).defer();return}$("sidebarPanel").select(".!
 on").inv
oke("removeClassName","on");var a=$(b);if(!a){return}if(!a.match("LI")){a=a.up();if(!a){return}}a.addClassName("on");a.ancestors().find(function(c){if(c.hasClassName("subfolders")){this._toggleSubFolder(c.id.substring(3),"exp")}else{return(c.id=="foldersSidebar")}},this)},iframeContent:function(b,d){if(b===null){b=d}var a=$("dimpmain_portal"),c;if(!a){DimpCore.showNotifications([{type:"horde.error",message:"Bad portal!"}]);return}c=new Element("IFRAME",{id:"iframe"+b,className:"iframe",frameBorder:0,src:d});this._resizeIE6Iframe(c);if(b=="options"){c.observe("load",function(){$("iframeoptions").contentWindow.document.getElementById("menu").style.display="none"})}a.insert(c)},msgWindow:function(b){this.updateUnseenUID(b,0);var a=DIMP.conf.message_url;a+=(a.include("?")?"&":"?")+$H({folder:b.view,uid:b.imapuid}).toQueryString();DimpCore.popupWindow(a,"msgview"+b.view+b.imapuid)},composeMailbox:function(a){var b=this.viewport.getSelected();if(!b.size()){return}b.get("dataob").ea
 ch(function(c){DimpCore.compose(a,{folder:c.view,uid:c.imapuid})})},loadFolder:function(b,a){if(!this.viewport){this._createViewPort()}if(!a){this.resetSelected();if(this.folder==b){this.searchfilterClear(false);return}this.searchfilterClear(true);$("folderName").update(DIMP.text.loading);$("msgHeader").update();this.folderswitch=true;this.folder=b}this.viewport.loadView(b,{folder:b},this.uid?{imapuid:DimpCore.toUIDString(this.uid,b)}:null,a)},_createViewPort:function(){var b=$("msgList_filter"),a=this.setMessageListTitle.bind(this);this.viewport=new ViewPort({content_container:"msgList",empty_container:"msgList_empty",error_container:"msgList_error",fetch_action:"ListMessages",template:this.message_list_template,buffer_pages:DIMP.conf.buffer_pages,limit_factor:DIMP.conf.limit_factor,viewport_wait:DIMP.conf.viewport_wait,show_split_pane:this.showPreview,split_pane:"previewPane",splitbar:"splitBar",content_class:"msglist",row_class:"msgRow",selected_class:"selectedRow",ajaxRe
 quest:DimpCore.doAction.bind(DimpCore),norows:true,onScrollI!
 dle:a,on
Slide:a,onViewChange:function(){DimpCore.addGC(this.viewport.visibleRows())}.bind(this),onContent:function(f){var e,d,c=((this.viewport.getMetaData("sortby")==DIMP.conf.sortthread)&&this.viewport.getMetaData("thread"));if(this.viewport.isFiltering()){d=this.sfilters.get(this._getSearchfilterField()).capitalize();e=new RegExp("("+$F("msgList_filter")+")","i")}f.get("dataob").each(function(k){var h,i,g,j=$(k.domid);if(c&&c[k.imapuid]){h=j.down(".msgSubject");i=h.cloneNode(false);g=c[k.imapuid];$R(0,g.length,true).each(function(l){i.insert($($("thread_img_"+g.charAt(l)).cloneNode(false)).writeAttribute("id",""))});h.replace(i.insert(h.getText().escapeHTML()))}if(k.atc){j.down(".msgSize").insert({top:$($("atc_img_"+k.atc).cloneNode(false)).writeAttribute("id","")})}DimpCore.addMouseEvents({id:k.domid,type:k.menutype});if(d=="From"||d=="Subject"){h=j.down(".msg"+d);h.update(h.getText().escapeHTML().gsub(e,'<span class="searchMatch">#{1}</span>'))}},this);this.setMessageListTitle()
 }.bind(this),onComplete:function(){var e,c,d=this.viewport.getMetaData("label");if(this.uid){e=this.viewport.getViewportSelection().search({imapuid:{equal:[this.uid]},view:{equal:[this.folder]}});if(e.size()){this.viewport.scrollTo(e.get("rownum").first());this.viewport.select(e)}}else{if(this.offset){this.viewport.select(this.viewport.createSelection("rownum",this.offset))}}this.offset=this.uid=null;d=this.viewport.getMetaData("label");if(d){$("folderName").update(d)}if(this.folderswitch){this.folderswitch=false;if(this.folder==DIMP.conf.spam_folder){if(!DIMP.conf.spam_spamfolder&&DimpCore.buttons.indexOf("button_spam")!=-1){[$("button_spam").up(),$("ctx_message_spam")].invoke("hide")}if(DimpCore.buttons.indexOf("button_ham")!=-1){[$("button_ham").up(),$("ctx_message_ham")].invoke("show")}}else{if(DimpCore.buttons.indexOf("button_spam")!=-1){[$("button_spam").up(),$("ctx_message_spam")].invoke("show")}if(DimpCore.buttons.indexOf("button_ham")!=-1){if(DIMP.conf.ham_spamfolde
 r){[$("button_ham").up(),$("ctx_message_ham")].invoke("hide"!
 )}else{[
$("button_ham").up(),$("ctx_message_ham")].invoke("show")}}}}else{if(this.filtertoggle){if(this.filtertoggle==1&&this.viewport.getMetaData("sortby")==DIMP.conf.sortthread){c=DIMP.conf.sortdate}this.filtertoggle=0}}this.setSortColumns(c);if(this.viewport.isFiltering()){this.resetSelected();this.updateTitle()}else{this.setFolderLabel(this.folder,this.viewport.getMetaData("unseen"))}}.bind(this),onFetch:this.msgListLoading.bind(this,true),onEndFetch:this.msgListLoading.bind(this,false),onWait:function(){if($("dimpmain_folder").visible()){DimpCore.showNotifications([{type:"horde.warning",message:DIMP.text.listmsg_wait}])}},onFail:function(){if($("dimpmain_folder").visible()){DimpCore.showNotifications([{type:"horde.error",message:DIMP.text.listmsg_timeout}])}this.msgListLoading(false)}.bind(this),onFirstContent:function(){this.clearPreviewPane();$("msgList").observe("dblclick",this._handleMsgListDblclick.bindAsEventListener(this))}.bind(this),onClearRows:function(c){c.each(functi
 on(d){var e=$(d).down("div.msCheck");if(e){DimpCore.addGC(e)}if(d.id){DimpCore.removeMouseEvents(d)}})},onBeforeResize:function(){var c=this.viewport.getSelected();this.isvisible=(c.size()==1)&&(this.viewport.isVisible(c.get("rownum").first())==0)}.bind(this),onAfterResize:function(){if(this.isvisible){this.viewport.scrollTo(this.viewport.getSelected().get("rownum").first())}}.bind(this),selectCallback:this._select.bind(this),deselectCallback:this._deselect.bind(this)});if(!this.showPreview){$("msgList").addClassName("msglistNoPreview")}this.viewport.addFilter("ListMessages",this._addSearchfilterParams.bind(this));b.observe("keyup",this._searchfilterOnKeyup.bind(this));b.observe("focus",this._searchfilterOnFocus.bind(this));b.observe("blur",this._searchfilterOnBlur.bind(this));b.addClassName("msgFilterDefault")},_addMouseEvents:function(b,c){var a;switch(c.type){case"draft":case"message":new Drag(c.id,this._msgDragConfig);a=$(c.id).down("div.msCheck");if(a.visible()){a.obser
 ve("mousedown",this.bcache.get("handleMLC")||this.bcache.set!
 ("handle
MLC",this._handleMsgListCheckbox.bindAsEventListener(this)));a.observe("contextmenu",Event.stop)}break;case"container":case"folder":new Drag(c.id,this._folderDragConfig);break;case"special":c.type="folder";break}c.onShow=this.bcache.get("onMS")||this.bcache.set("onMS",this._onMenuShow.bind(this));b(c)},_removeMouseEvents:function(b,a){var c,e=$(a).readAttribute("id");if(e&&(c=DragDrop.Drags.get_drag(e))){c.destroy()}b(a)},_onMenuShow:function(a){var e,c,b,d;switch(a.ctx){case"ctx_folder":e=$("ctx_folder_create","ctx_folder_rename","ctx_folder_delete");c=DimpCore.DMenu.element();if(c.readAttribute("mbox")=="INBOX"){e.invoke("hide")}else{if(DIMP.conf.fixed_folders.indexOf(c.readAttribute("mbox"))!=-1){e.shift();e.invoke("hide")}else{e.invoke("show")}}if(c.hasAttribute("u")){$("ctx_folder_poll").hide();$("ctx_folder_nopoll").show()}else{$("ctx_folder_poll").show();$("ctx_folder_nopoll").hide()}break;case"ctx_message":[$("ctx_message_reply_list")].invoke(this.viewport.createSelec
 tion("domid",a.id).get("dataob").first().listmsg?"show":"hide");break;case"ctx_reply":d=this.viewport.getSelected();if(d.size()==1){b=d.get("dataob").first()}[$("ctx_reply_reply_list")].invoke(b&&b.listmsg?"show":"hide");break;case"ctx_otheractions":$("oa_seen","oa_unseen","oa_flagged","oa_clear","oa_sep1","oa_blacklist","oa_whitelist","oa_sep2","oa_undelete").compact().invoke(this.viewport.getSelected().size()?"show":"hide");break}return true},_onResize:function(){if(this.viewport){this.viewport.onResize()}this._resizeIE6()},_handleMsgListDblclick:function(b){var a=this._getMsgRow(b);if(!a){return}var c=this.viewport.createSelection("domid",a.id).get("dataob").first();c.draft?DimpCore.compose("resume",{folder:c.view,uid:c.imapuid}):this.msgWindow(c);b.stop()},_handleMsgListCheckbox:function(b){var a=this._getMsgRow(b);if(!a){return}this.msgSelect(a.readAttribute("id"),{ctrl:true,right:true});b.stop()},_getMsgRow:function(a){a=a.element();if(a&&!a.hasClassName("msgRow")){a=a
 .up(".msgRow")}return a},updateTitle:function(){var b,a,c;if!
 (this.vi
ewport.isFiltering()){a=DIMP.text.search+" :: "+this.viewport.getMetaData("total_rows")+" "+DIMP.text.resfound}else{b=$(this.getFolderId(this.folder));if(b){c=b.readAttribute("u");a=b.readAttribute("l");if(c>0){a+=" ("+c+")"}}else{a=this.viewport.getMetaData("label")}}DimpCore.setTitle(a)},sort:function(d){if(this.viewport.getMetaData("sortlimit")){return}var b,c,a=d.element();if(!a.hasAttribute("sortby")){a=a.up("[sortby]");if(!a){return}}c=parseInt(a.readAttribute("sortby"),10);if(c==this.viewport.getMetaData("sortby")){b={sortdir:(this.viewport.getMetaData("sortdir")?0:1)};this.viewport.setMetaData({sortdir:b.sortdir})}else{b={sortby:c};this.viewport.setMetaData({sortby:b.sortby})}this.setSortColumns(c);this.viewport.reload(b)},setSortColumns:function(c){var b,a=$("msglistHeader");if(Object.isUndefined(c)){c=this.viewport.getMetaData("sortby")}b=a.down("small[sortby="+c+"]");if(b&&b.up().visible()){b.up(1).childElements().invoke("toggle")}b=a.down("div.msgFrom a");if((this
 .viewport.isFiltering()&&this.fspecial)||this.viewport.getMetaData("special")){b.hide().next().show()}else{b.show().next().hide()}b=a.down("div.msgSubject a");if(this.viewport.isFiltering()||this.viewport.getMetaData("nothread")||this.viewport.getMetaData("sortlimit")){b.show().next().hide();b.down().hide()}else{b.down().show()}a.childElements().invoke("removeClassName","sortup").invoke("removeClassName","sortdown");a.down("div a[sortby="+c+"]").up().addClassName(this.viewport.getMetaData("sortdir")?"sortup":"sortdown")},togglePreviewPane:function(){this.showPreview=!this.showPreview;$("previewtoggle").setText(this.showPreview?DIMP.text.hide_preview:DIMP.text.show_preview);[$("msgList")].invoke(this.showPreview?"removeClassName":"addClassName","msglistNoPreview");DimpCore.doAction("SetPrefValue",{pref:"show_preview",value:this.showPreview?1:0});this.viewport.showSplitPane(this.showPreview);if(this.showPreview){this.initPreviewPane()}this.updateTitle()},_loadPreview:function(
 c){var a=$("previewPane"),b;if(!a.visible()){return}if(this.!
 pp&&this
.pp==c){return}this.pp=c;if(this.ppfifo.indexOf(c.vp_id)!=-1){return this._loadPreviewCallback(this.ppcache.get(c.vp_id))}b=a.positionedOffset();$("msgLoading").setStyle({position:"absolute",top:(b.top+10)+"px",left:(b.left+10)+"px"}).show();DimpCore.doAction("ShowPreview",{},DimpCore.toUIDArray(this.viewport.createSelection("dataob",c)),this.bcache.get("loadPC")||this.bcache.set("loadPC",this._loadPreviewCallback.bind(this)))},_loadPreviewCallback:function(resp){var row,search,tmp,tmp2,pm=$("previewMsg"),r=resp.response;if(!r.error){search=this.viewport.getViewportSelection(r.view).search({vp_id:{equal:[r.uid]}});if(search.size()){row=search.get("dataob").first();this.updateUnseenUID(row,0)}}if(this.pp&&this.pp.vp_id!=r.uid){return}if(r.error||this.viewport.getSelected().size()!=1){if(r.error){DimpCore.showNotifications([{type:r.errortype,message:r.error}])}this.clearPreviewPane();return}this._expirePPCache([r.uid]);this.ppcache.set(r.uid,resp);this.ppfifo.push(r.uid);DimpCo
 re.removeAddressLinks(pm);DIMP.conf.msg_index=r.index;DIMP.conf.msg_folder=r.folder;DIMP.conf.msg_source_link=r.source_link;tmp=pm.select(".subject");tmp.invoke("update",r.subject);switch(r.priority){case"high":case"low":tmp.invoke("insert",{top:$($(r.priority+"_priority_img").cloneNode(false)).writeAttribute("id",false)});break}pm.select(".from").invoke("update",r.from);$("msgHeadersColl").select(".date").invoke("update",r.minidate);$("msgHeaderDate").select(".date").invoke("update",r.fulldate);["to","cc"].each(function(a){if(r[a]){pm.select("."+a).invoke("update",r[a])}[$("msgHeader"+a.capitalize())].invoke(r[a]?"show":"hide")});$("msgHeadersColl").select(".attachmentImage").invoke(r.atc_label?"show":"hide");if(r.atc_label){tmp=$("msgAtc").show().down(".label");tmp2=$("partlist");tmp2.hide().previous().update(r.atc_label+" "+r.atc_download);if(r.atc_list){$("partlist_col").show();$("partlist_exp").hide();tmp.down().hide().next().show();tmp2.update(r.atc_list)}else{tmp.down
 ().show().next().hide()}}else{$("msgAtc").hide()}$("msgBody"!
 ).down()
.update(r.msgtext);$("msgLoading","previewInfo").invoke("hide");$("previewPane").scrollTop=0;pm.show();if(r.js){eval(r.js.join(";"))}DimpCore.buildAddressLinks(pm);this._addHistory("msg:"+row.view+":"+row.imapuid)},initPreviewPane:function(){var a=this.viewport.getSelected();if(a.size()!=1){this.clearPreviewPane()}else{this._loadPreview(a.get("dataob").first())}},clearPreviewPane:function(){$("msgLoading","previewMsg").invoke("hide");$("previewInfo").show();this.pp=null},_expirePPCache:function(a){this.ppfifo=this.ppfifo.without(a);a.each(this.ppcache.unset.bind(this.ppcache));if(this.ppfifo.size()>20){this.ppcache.unset(this.ppfifo.shift())}},updateUnseenUID:function(b,e){var c,a,d=0;if(!b.bg){return false}a=b.bg.match(this.unseen_regex);if((e&&a)||(!e&&!a)){return false}c=this.viewport.createSelection("dataob",b);if(e){this.viewport.updateFlag(c,"unseen",true);++d}else{this.viewport.updateFlag(c,"unseen",false);--d}return this.updateUnseenStatus(b.view,d)},updateUnseenStatu
 s:function(b,c){if(c==0){return false}var a=parseInt($(this.getFolderId(b)).readAttribute("u"))+c;this.viewport.setMetaData({unseen:a});this.setFolderLabel(b,a);return true},setMessageListTitle:function(){var b,a=this.viewport.getMetaData("total_rows");if(a>0){b=this.viewport.currentOffset();$("msgHeader").update(DIMP.text.messages+" "+(b+1)+" - "+(Math.min(b+this.viewport.getPageSize(),a))+" "+DIMP.text.of+" "+a)}else{$("msgHeader").update(DIMP.text.nomessages)}},setFolderLabel:function(b,c){var a,d=this.getFolderId(b);a=$(d);if(!a||!a.hasAttribute("u")){return}c=parseInt(c);a.writeAttribute("u",c);if(b=="INBOX"&&window.fluid){window.fluid.setDockBadge(c?c:"")}$(d+"_label").update((c>0)?new Element("STRONG").insert(a.readAttribute("l")).insert(" ").insert(new Element("SPAN",{className:"count",dir:"ltr"}).insert("("+c+")")):a.readAttribute("l"));if(this.folder==b){this.updateTitle()}},getFolderId:function(a){return"fld"+decodeURIComponent(a).replace(/_/g,"__").replace(/
 \W/g,"_")},getSubFolderId:function(a){return"sub"+a},pollFol!
 ders:fun
ction(){this.setPollFolders();var a={};if(this.folder&&$("dimpmain_folder").visible()){a=this.viewport.addRequestParams({})}$("button_checkmail").setText("["+DIMP.text.check+"]");DimpCore.doAction("PollFolders",a,[],this.bcache.get("pollFC")||this.bcache.set("pollFC",this._pollFoldersCallback.bind(this)))},_pollFoldersCallback:function(a){a=a.response;if(a.poll){$H(a.poll).each(function(b){this.setFolderLabel(b.key,b.value);if(this.viewport){this.viewport.setMetaData({unseen:b.value},b.key)}},this)}if(a.quota){$("quota").update(a.quota)}$("button_checkmail").setText(DIMP.text.getmail)},setPollFolders:function(){if(DIMP.conf.refresh_time){if(this.pollPE){this.pollPE.stop()}this.pollPE=new PeriodicalExecuter(this.pollFolders.bind(this),DIMP.conf.refresh_time)}},_portalCallback:function(b){if(b.response.linkTags){var a=$$("HEAD").first();b.response.linkTags.each(function(c){var d=new Element("LINK",{type:"text/css",rel:"stylesheet",href:c.href});if(c.media){d.media=c.media}a.ins
 ert(d)})}$("dimpmain_portal").update(b.response.portal);$("dimpmain_portal").select("h1.header a").each(this.bcache.get("portalClkLink")||this.bcache.set("portalClkLink",function(c){c.observe("click",function(f,g){this.go("app:"+g.readAttribute("app"));f.stop()}.bindAsEventListener(this,c))}.bind(this)))},_searchfilterOnKeyup:function(){if(this.searchobserve){clearTimeout(this.searchobserve)}this.searchobserve=(this.bcache.get("searchfilterR")||this.bcache.set("searchfilterR",this.searchfilterRun.bind(this))).delay(0.5)},searchfilterRun:function(){if(!this.viewport.isFiltering()){this.filtertoggle=1;this.fspecial=this.viewport.getMetaData("special")}this.viewport.runFilter($F("msgList_filter"))},_searchfilterOnFocus:function(){var a=$("qoptions");if($("msgList_filter").hasClassName("msgFilterDefault")){this._setFilterText(false)}if(!a.visible()){$("sf_current").update(this.viewport.getMetaData("label"));this._setSearchfilterParams(this.viewport.getMetaData("special")?"to":"f
 rom","msg");this._setSearchfilterParams("current","folder");!
 a.show()
;this.viewport.onResize()}},_searchfilterOnBlur:function(){if(!$F("msgList_filter")){this._setFilterText(true)}},searchfilterClear:function(a){if(!$("qoptions").visible()){return}if(this.searchobserve){clearTimeout(this.searchobserve);this.searchobserve=null}this._setFilterText(true);$("qoptions").hide();this.filtertoggle=2;this.resetSelected();this.viewport.onResize(a);this.viewport.stopFilter(a)},_setFilterText:function(b){var a=$("msgList_filter");if(b){a.setValue(DIMP.text.search);a.addClassName("msgFilterDefault")}else{a.setValue("");a.removeClassName("msgFilterDefault")}},_setSearchfilterParams:function(d,a){var b=(a=="folder")?this.sfiltersfolder:this.sfilters;b.keys().each(function(c){$(c).writeAttribute("className",(d==b.get(c))?"qselected":"")})},updateSearchfilter:function(b,a){this._setSearchfilterParams(b,a);if($F("msgList_filter")){this.viewport.runFilter()}},_addSearchfilterParams:function(){var a=this.sfiltersfolder.keys().find(function(b){return $(b).hasClass
 Name("qselected")});return{searchfolder:this.sfiltersfolder.get(a),searchmsg:this.sfilters.get(this._getSearchfilterField())}},_getSearchfilterField:function(){return this.sfilters.keys().find(function(a){return $(a).hasClassName("qselected")})},toggleButtons:function(){var a=(this.selectedCount()==0);DimpCore.buttons.each(function(c){var d=$(c);if(d){[d.up()].invoke(a?"addClassName":"removeClassName","disabled");DimpCore.DMenu.disable(c+"_img",true,a)}})},_folderDropHandler:function(c,d){var g,f,e,b=c.readAttribute("mbox"),a=c.readAttribute("ftype");if(d.hasClassName("folder")){g=(c==$("dropbase"));if(g||(a!="special"&&!this.isSubfolder(d,c))){DimpCore.doAction("RenameFolder",{old_name:d.readAttribute("mbox"),new_parent:g?"":b,new_name:d.readAttribute("l")},[],this.bcache.get("folderC")||this.bcache.set("folderC",this._folderCallback.bind(this)))}}else{if(a!="container"){f=this.viewport.getSelected();if(f.size()){e=f}else{if(d.readAttribute("mbox")!=b){e=this.viewport.creat
 eSelection("domid",d.id)}}if(e.size()&&this.folder!=b){this.!
 viewport
.updateFlag(e,"deletedmsg",true);DimpCore.doAction("MoveMessage",this.viewport.addRequestParams({tofld:b}),DimpCore.toUIDArray(e),this.bcache.get("deleteC")||this.bcache.set("deleteC",this._deleteCallback.bind(this)))}}}},_dragCaption:function(){var a=this.selectedCount();return a+" "+(a==1?DIMP.text.message:DIMP.text.messages)},_keydownHandler:function(f){if(!$("dimpmain_folder").visible()||f.findElement("FORM")||RedBox.overlayVisible()){return}var i,h,b,g,d,a=f.keyCode||f.charCode,c=this.viewport.getSelected();switch(a){case Event.KEY_DELETE:case Event.KEY_BACKSPACE:b=c.get("dataob");if(f.shiftKey){this.moveSelected((b.last().rownum==this.viewport.getMetaData("total_rows"))?(b.first().rownum-1):(b.last().rownum+1),true)}this.flag("deleted",b);f.stop();break;case Event.KEY_UP:case Event.KEY_DOWN:if(f.shiftKey&&this.lastrow!=-1){g=this.viewport.createSelection("rownum",this.lastrow+((a==Event.KEY_UP)?-1:1));if(g.size()){g=g.get("dataob").first();this.viewport.scrollTo(g.rownu
 m);this.msgSelect(g.domid,{shift:true})}}else{this.moveSelected(a==Event.KEY_UP?-1:1)}f.stop();break;case Event.KEY_PAGEUP:case Event.KEY_PAGEDOWN:if(!f.ctrlKey&&!f.shiftKey&&!f.altKey&&!f.metaKey){h=this.viewport.getPageSize()-1;move=h*(a==Event.KEY_PAGEUP?-1:1);if(c.size()==1){i=this.viewport.currentOffset();d=c.get("rownum").first()-1;switch(a){case Event.KEY_PAGEUP:if(i!=d){move=i-d}break;case Event.KEY_PAGEDOWN:if((i+h)!=d){move=i+h-d}break}}this.moveSelected(move);f.stop()}break;case Event.KEY_HOME:case Event.KEY_END:this.moveSelected(a==Event.KEY_HOME?1:this.viewport.getMetaData("total_rows"),true);f.stop();break;case Event.KEY_RETURN:if(!f.element().match("input")){if(c.size()==1){this.msgWindow(c.get("dataob").first())}}f.stop();break;case 65:case 97:if(f.ctrlKey){this.selectAll();f.stop()}break}},renameFolder:function(a){if(Object.isUndefined(a)){return}a=$(a);var b=this._createFolderForm(function(c){this._folderAction(a,c,"rename");return false}.bindAsEventListene
 r(this),DIMP.text.rename_prompt);b.down("input").setValue(a.!
 readAttr
ibute("l"))},createBaseFolder:function(){this._createFolderForm(function(a){this._folderAction("",a,"create");return false}.bindAsEventListener(this),DIMP.text.create_prompt)},createSubFolder:function(a){if(Object.isUndefined(a)){return false}this._createFolderForm(function(b){this._folderAction($(a),b,"createsub");return false}.bindAsEventListener(this),DIMP.text.createsub_prompt)},_createFolderForm:function(a,b){var c=new Element("FORM",{action:"#",id:"RB_folder"}).insert(new Element("P").insert(b)).insert(new Element("INPUT",{type:"text",size:15})).insert(new Element("INPUT",{type:"button",className:"button",value:DIMP.text.ok}).observe("click",a)).insert(new Element("INPUT",{type:"button",className:"button",value:DIMP.text.cancel}).observe("click",this.bcache.get("closeRB")||this.bcache.set("closeRB",this._closeRedBox.bind(this)))).observe("keydown",function(d){if((d.keyCode||d.charCode)==Event.KEY_RETURN){d.stop();a(d)}});RedBox.overlay=true;RedBox.onDisplay=Form.focusFi
 rstElement.curry(c);RedBox.showHtml(c);return c},_closeRedBox:function(){var a=RedBox.getWindowContents();DimpCore.addGC([a,a.descendants()].flatten());RedBox.close()},_folderAction:function(b,d,h){this._closeRedBox();var c,g,f,a=d.findElement("form");f=$F(a.down("input"));if(f){switch(h){case"rename":if(b.readAttribute("l")!=f){c="RenameFolder";g={old_name:b.readAttribute("mbox"),new_parent:b.up().hasClassName("folderlist")?"":b.up(1).previous().readAttribute("mbox"),new_name:f}}break;case"create":case"createsub":c="CreateFolder";g={folder:f};if(h=="createsub"){g.parent=b.readAttribute("mbox")}break}if(c){DimpCore.doAction(c,g,[],this.bcache.get("folderC")||this.bcache.set("folderC",this._folderCallback.bind(this)))}}},_folderCallback:function(a){a=a.response;a.d.each(this.deleteFolder.bind(this));a.c.each(this.changeFolder.bind(this));a.a.each(this.createFolder.bind(this))},_deleteCallback:function(b){this.msgListLoading(false);this._pollFoldersCallback(b);if(!b.response.u
 ids||b.response.folder!=this.folder){return}var a=this.viewp!
 ort.getV
iewportSelection().search({view:{equal:[b.response.folder]},imapuid:{equal:b.response.uids[b.response.folder]}});if(a.size()){if(b.response.remove){this.viewport.remove(a,{cacheid:b.response.cacheid,noupdate:b.response.viewport});this._expirePPCache(a.get("uid"))}else{this.viewport.updateFlag(a,"deletedmsg",true)}}},_emptyFolderCallback:function(a){if(a.response.mbox){if(this.folder==a.response.mbox){this.viewport.reload();this.clearPreviewPane()}this.setFolderLabel(a.response.mbox,0)}},_flagAllCallback:function(a){if(a.response.mbox){this.setFolderLabel(a.response.mbox,a.response.u)}},_folderLoadCallback:function(b){this._folderCallback(b);var d=$("specialfolders","normalfolders").compact(),c=$("normalfolders"),a=c.getStyle("max-height");d.invoke("observe","click",this._handleFolderMouseEvent.bindAsEventListener(this,"click"));d.invoke("observe","mouseover",this._handleFolderMouseEvent.bindAsEventListener(this,"over"));if(DIMP.conf.is_ie6){d.invoke("observe","mouseout",this.
 _handleFolderMouseEvent.bindAsEventListener(this,"out"))}$("foldersLoading").hide();$("foldersSidebar").show();if(a!==null||(Prototype.Browser.IE&&Object.isUndefined(a)&&(c.getStyle("height")=="0px"))){this._sizeFolderlist();Event.observe(window,"resize",this._sizeFolderlist.bind(this))}if(b.response.quota){$("quota").update(b.response.quota)}},_handleFolderMouseEvent:function(f,d){var c,b=f.element(),a=b.up(".folder")||b.up(".custom");if(!a){return}c=a.readAttribute("ftype");switch(d){case"over":if(DIMP.conf.is_ie6){a.addClassName("over")}if(c&&!this.mo_sidebar.get(a.id)){DimpCore.addMouseEvents({id:a.id,type:c});this.mo_sidebar.set(a.id,1)}break;case"out":a.removeClassName("over");break;case"click":if(b.hasClassName("exp")||b.hasClassName("col")){this._toggleSubFolder(a.id,"tog")}else{switch(c){case"container":f.stop();break;case"folder":case"special":f.stop();return this.go("folder:"+a.readAttribute("mbox"));break}}break}},_toggleSubFolder:function(b,c){b=$(b);var a=$(thi
 s.getSubFolderId(b.id));if(a&&(c=="tog"||(c=="exp"&&!a.visib!
 le())||(
c=="col"&&a.visible()))){b.firstDescendant().writeAttribute({className:a.toggle().visible()?"col":"exp"})}if(b.descendantOf("specialfolders")){this._sizeFolderlist()}},createFolder:function(c){var b,f,i,g,h,e=this.getFolderId(c.m),a=decodeURIComponent(c.m),d=this.getSubFolderId(e),j=$(d);i=new Element("LI",{className:"folder",id:e,l:c.l,mbox:a,ftype:((c.co)?"container":((c.s)?"special":"folder"))});b=new Element("DIV",{className:c.cl||"base",id:e+"_div"});if(c.i){b.update(c.i)}if(c.ch){b.writeAttribute({className:"exp"}).observe("mouseover",this.bcache.get("mo_folder")||this.bcache.set("mo_folder",function(k){k=k.element();if(DragDrop.Drags.drag&&k.hasClassName("exp")){this._toggleSubFolder(k.up(),"exp")}}.bindAsEventListener(this)))}i.insert(b).insert(new Element("A",{id:e+"_label",title:c.l}).insert(c.l));if(j){if(j.insert({before:i}).visible()){b.removeClassName("exp").addClassName("col")}}else{if(c.s){h=$("specialfolders")}else{h=$(this.getSubFolderId(this.getFolderId(c.p
 a)));h=(h)?h.down("UL"):$("normalfolders")}g=a.toLowerCase();f=h.childElements().find(function(k){var l=k.readAttribute("mbox");return l&&(!c.s||l!="INBOX")&&(g<l.toLowerCase())});if(f){f.insert({before:i})}else{h.insert(i)}if(c.ch){i.insert({after:new Element("LI",{className:"subfolders",id:d}).insert(new Element("UL")).hide()})}}new Drop(i,this._folderDropConfig);if(c.po){i.writeAttribute("u","");this.setFolderLabel(a,c.u)}},deleteFolder:function(a){var b=decodeURIComponent(a),c;if(this.folder==b){this.go("folder:INBOX")}c=this.getFolderId(a);this.deleteFolderElt(c,true)},changeFolder:function(b){var d=this.getFolderId(b.m),a=$(d+"_div"),c=a&&a.hasClassName("col");this.deleteFolderElt(d,!b.ch);if(b.co&&this.folder==b.m){this.go("folder:INBOX")}this.createFolder(b);if(b.ch&&c){a.removeClassName("exp").addClassName("col")}},deleteFolderElt:function(d,b){var c=$(d);DimpCore.addGC($(c,d+"_div",d+"_label"));if(b){var a=$(this.getSubFolderId(d));if(a){a.remove()}}[DragDrop.Drags
 .get_drag(d),DragDrop.Drops.get_drop(d)].compact().invoke("d!
 estroy")
;DimpCore.removeMouseEvents(c);this.mo_sidebar.unset(d,1);DimpCore.addGC(c);if(this.viewport){this.viewport.deleteView(d)}c.remove()},_sizeFolderlist:function(){var a=$("normalfolders");a.setStyle({height:(document.viewport.getHeight()-a.cumulativeOffset()[1]-10)+"px"})},flag:function(f,d,e){var c,b,h,g=[],a=1;if(d){if(Object.isUndefined(e)){h=this.viewport.createSelection("dataob",d)}else{h=this.viewport.getViewportSelection().search({imapuid:{equal:[d]},view:{equal:[e]}});if(!h.size()&&e!=this.folder){h=this.viewport.getViewportSelection(e).search({imapuid:{equal:[d]}})}}}else{h=this.viewport.getSelected()}switch(f){case"allUnseen":case"allSeen":DimpCore.doAction((f=="allUnseen")?"MarkFolderUnseen":"MarkFolderSeen",{folder:e},[],this.bcache.get("flagAC")||this.bcache.set("flagAC",this._flagAllCallback.bind(this)));if(e==this.folder){this.viewport.updateFlag(this.createSelection("rownum",$A($R(1,this.viewport.getMetaData("total_rows")))),"unseen",f=="allUnseen")}break;case"d
 eleted":case"undeleted":case"spam":case"ham":case"blacklist":case"whitelist":if(!h.size()){break}if(f=="deleted"){h=h.search({isdel:{not:[true]}});if(!h.size()){break}h.set({isdel:true})}else{if(f=="undeleted"){h.set({isdel:false})}}b=this.viewport.addRequestParams({});if(f=="deleted"||f=="undeleted"){this.viewport.updateFlag(h,"deletedmsg",f=="deleted")}if(f=="undeleted"){DimpCore.doAction("UndeleteMessage",b,DimpCore.toUIDArray(h))}else{c={deleted:"DeleteMessage",spam:"ReportSpam",ham:"ReportHam",blacklist:"Blacklist",whitelist:"Whitelist"};DimpCore.doAction(c[f],b,DimpCore.toUIDArray(h),this.bcache.get("deleteC")||this.bcache.set("deleteC",this._deleteCallback.bind(this)),{asynchronous:!(d&&e)});if(f=="spam"||f=="ham"){this.msgListLoading(true)}}break;case"unseen":case"seen":if(!h.size()){break}b={folder:this.folder,messageFlag:"-seen"};if(f=="seen"){a=0;b.messageFlag="seen"}h.get("dataob").each(function(i){if(this.updateUnseenUID(i,a)){g.push(i)}},this);if(g.size()){Dimp
 Core.doAction("MarkMessage",b,DimpCore.toUIDArray(this.viewp!
 ort.crea
teSelection("dataob",g)))}break;case"flagged":case"clear":if(!h.size()){break}b={folder:this.folder,messageFlag:((f=="flagged")?"flagged":"-flagged")};this.viewport.updateFlag(h,"flagged",f=="flagged");DimpCore.doAction("MarkMessage",b,DimpCore.toUIDArray(h));break;case"answered":this.viewport.updateFlag(h,"answered",true);this.viewport.updateFlag(h,"flagged",false);break}},purgeDeleted:function(){DimpCore.doAction("PurgeDeleted",this.viewport.addRequestParams({}),[],this.bcache.get("deleteC")||this.bcache.set("deleteC",this._deleteCallback.bind(this)))},modifyPollFolder:function(a,b){DimpCore.doAction("ModifyPollFolder",{folder:a,add:(b)?1:0},[],this.bcache.get("modifyPFC")||this.bcache.set("modifyPFC",this._modifyPollFolderCallback.bind(this)))},_modifyPollFolderCallback:function(a){a=a.response;var b=a.folder,d,c={response:{poll:{}}};d=$(this.getFolderId(b));if(a.add){c.response.poll[b]=a.poll.u;d.writeAttribute("u",0)}else{c.response.poll[b]=0}this._pollFoldersCallback(c)
 ;if(!a.add){d.removeAttribute("u")}},msgListLoading:function(a){var b;if(this.fl_visible!=a){this.fl_visible=a;if(a){b=$("msgList").positionedOffset();$("folderLoading").setStyle({position:"absolute",top:(b.top+10)+"px",left:(b.left+10)+"px"});Effect.Appear("folderLoading",{duration:0.2});$(document.body).setStyle({cursor:"progress"})}else{Effect.Fade("folderLoading",{duration:0.2});$(document.body).setStyle({cursor:"default"})}}},isSubfolder:function(b,d){var a=$(this.getSubFolderId(b.readAttribute("id")));return a&&d.descendantOf(a)},_onLoad:function(){var b=DimpCore.clickObserveHandler,a;if(Horde.dhtmlHistory.initialize()){Horde.dhtmlHistory.addListener(this.go.bind(this))}this._setFilterText(true);if(!Horde.dhtmlHistory.getCurrentLocation()){if(DIMP.conf.login_view=="inbox"){this.go("folder:INBOX")}else{this.go("portal");if(DIMP.conf.background_inbox){this.loadFolder("INBOX",true)}}}DimpCore.addPopdown("button_reply","reply");DimpCore.DMenu.disable("button_reply_img",tru
 e,true);DimpCore.addPopdown("button_forward","forward");Dimp!
 Core.DMe
nu.disable("button_forward_img",true,true);DimpCore.addPopdown("button_other","otheractions");a=$("logo");if(a.visible()){b({d:a.down("a"),f:this.go.bind(this,"portal")})}a=$("dimpbarActions");b({d:a.down(".composelink"),f:DimpCore.compose.bind(DimpCore,"new")});b({d:a.down(".refreshlink"),f:this.pollFolders.bind(this)});a=$("serviceActions");["portal","options"].each(function(c){var e=$("app"+c);if(e){b({d:e,f:this.go.bind(this,c)})}},this);a=$("applogout");if(a){b({d:a,f:DimpCore.logout.bind(DimpCore)})}a=$("applicationfolders");if(a){a.select("ul li.custom a").each(function(c){b({d:c,f:this.go.bind(this,"app:"+c.readAttribute("app"))})},this)}b({d:$("newfolder"),f:this.createBaseFolder.bind(this)});new Drop("dropbase",this._folderDropConfig);a=$("hometab");if(a){b({d:a,f:this.go.bind(this,"portal")})}$("tabbar").select("a.applicationtab").each(function(c){b({d:c,f:this.go.bind(this,"app:"+c.readAttribute("app"))})},this);b({d:$("button_reply"),f:this.composeMailbox.bind(th
 is,"reply"),ns:true});b({d:$("button_forward"),f:this.composeMailbox.bind(this,DIMP.conf.forward_default),ns:true});["spam","ham","deleted"].each(function(c){var e=$("button_"+c);if(e){b({d:e,f:this.flag.bind(this,c)})}},this);b({d:$("button_compose"),f:DimpCore.compose.bind(DimpCore,"new")});b({d:$("button_other"),f:function(c){DimpCore.DMenu.trigger(c.findElement("A").next(),true)},p:true});b({d:$("qoptions").down(".qclose a"),f:this.searchfilterClear.bind(this,false)});["all","current"].each(function(c){var e=$("sf_"+c);if(e){b({d:e,f:this.updateSearchfilter.bind(this,c,"folder")})}},this);["msgall","from","to","subject"].each(function(c){b({d:$("sf_"+c),f:this.updateSearchfilter.bind(this,c,"msg")})},this);b({d:$("msglistHeader"),f:this.sort.bind(this),p:true});b({d:$("ctx_folder_create"),f:function(){this.createSubFolder(DimpCore.DMenu.element())}.bind(this),ns:true});b({d:$("ctx_folder_rename"),f:function(){this.renameFolder(DimpCore.DMenu.element())}.bind(this),ns:tru
 e});b({d:$("ctx_folder_empty"),f:function(){if(window.confir!
 m(DIMP.t
ext.empty_folder)){DimpCore.doAction("EmptyFolder",{folder:DimpCore.DMenu.element().readAttribute("mbox")},[],this._emptyFolderCallback.bind(this))}}.bind(this),ns:true});b({d:$("ctx_folder_delete"),f:function(){if(window.confirm(DIMP.text.delete_folder)){DimpCore.doAction("DeleteFolder",{folder:DimpCore.DMenu.element().readAttribute("mbox")},[],this.bcache.get("folderC")||this.bcache.set("folderC",this._folderCallback.bind(this)))}}.bind(this),ns:true});["ctx_folder_seen","ctx_folder_unseen"].each(function(c){b({d:$(c),f:function(d){this.flag(d,null,DimpCore.DMenu.element().readAttribute("mbox"))}.bind(this,c=="ctx_folder_seen"?"allSeen":"allUnseen"),ns:true})},this);["ctx_folder_poll","ctx_folder_nopoll"].each(function(c){b({d:$(c),f:function(d){this.modifyPollFolder(DimpCore.DMenu.element().readAttribute("mbox"),d)}.bind(this,c=="ctx_folder_poll"),ns:true})},this);b({d:$("ctx_container_create"),f:function(){this.createSubFolder(DimpCore.DMenu.element())}.bind(this),ns:true
 });b({d:$("ctx_container_rename"),f:function(){this.renameFolder(DimpCore.DMenu.element())}.bind(this),ns:true});["reply","reply_all","reply_list","forward_all","forward_body","forward_attachments"].each(function(c){b({d:$("ctx_message_"+c),f:this.composeMailbox.bind(this,c),ns:true})},this);["seen","unseen","flagged","clear","spam","ham","blacklist","whitelist","deleted","undeleted"].each(function(c){var e=$("ctx_message_"+c);if(e){b({d:e,f:this.flag.bind(this,c),ns:true})}},this);b({d:$("ctx_draft_resume"),f:this.composeMailbox.bind(this,"resume")});["flagged","clear","deleted","undeleted"].each(function(c){var e=$("ctx_draft_"+c);if(e){b({d:e,f:this.flag.bind(this,c),ns:true})}},this);["reply","reply_all","reply_list"].each(function(c){b({d:$("ctx_reply_"+c),f:this.composeMailbox.bind(this,c),ns:true})},this);["forward_all","forward_body","forward_attachments"].each(function(c){b({d:$("ctx_forward_"+c),f:this.composeMailbox.bind(this,c),ns:true})},this);b({d:$("previewtog
 gle"),f:this.togglePreviewPane.bind(this),ns:true});["seen",!
 "unseen"
,"flagged","clear","blacklist","whitelist","undeleted"].each(function(c){var e=$("oa_"+c);if(e){b({d:e,f:this.flag.bind(this,c),ns:true})}},this);b({d:$("oa_selectall"),f:this.selectAll.bind(this),ns:true});a=$("oa_purge_deleted");if(a){b({d:a,f:this.purgeDeleted.bind(this),ns:true})}$("expandHeaders","collapseHeaders").each(function(c){b({d:c,f:function(){$("msgHeadersColl","msgHeaders").invoke("toggle")},ns:true})},this);$("msg_newwin","msg_newwin_options").compact().each(function(c){b({d:c,f:function(){this.msgWindow(this.viewport.getViewportSelection().search({imapuid:{equal:[DIMP.conf.msg_index]},view:{equal:[DIMP.conf.msg_folder]}}).get("dataob").first())}.bind(this)})},this);DimpCore.messageOnLoad();this._resizeIE6()},_resizeIE6:function(){if(DIMP.conf.is_ie6){var a=parseInt($("sidebarPanel").getStyle("width"),10),b=document.viewport.getWidth()-a-30;$("normalfolders").setStyle({width:a+"px"});$("dimpmain").setStyle({width:b+"px"});$("msglist").setStyle({width:(b-5)+"px
 "});$("msgBody").setStyle({width:(b-25)+"px"});a=$("dimpmain_portal").down("IFRAME");if(a){this._resizeIE6Iframe(a)}}},_resizeIE6Iframe:function(a){if(DIMP.conf.is_ie6){a.setStyle({width:$("dimpmain").getStyle("width"),height:(document.viewport.getHeight()-20)+"px"})}}};DimpBase._msgDragConfig={scroll:"normalfolders",threshold:5,caption:DimpBase._dragCaption.bind(DimpBase),onStart:function(c,b){var a={right:b.isRightClick()},f=c.element.id;c.selectIfNoDrag=false;if(!a.right&&(b.ctrlKey||b.metaKey)){this.msgSelect(f,$H({ctrl:true}).merge(a).toObject())}else{if(b.shiftKey){this.msgSelect(f,$H({shift:true}).merge(a).toObject())}else{if(this.isSelected("domid",f)){if(!a.right&&this.selectedCount()){c.selectIfNoDrag=true}}else{this.msgSelect(f,a)}}}}.bind(DimpBase),onEnd:function(b,a){if(b.selectIfNoDrag&&!b.wasDragged){this.msgSelect(b.element.id,{right:a.isRightClick()})}}.bind(DimpBase)};DimpBase._folderDragConfig={ghosting:true,offset:{x:5,y:5},scroll:"normalfolders",threshol
 d:5,onDrag:function(b,a){if(!b.wasDragged){$("newfolder").hi!
 de();$("
dropbase").show();b.ghost.removeClassName("on")}},onEnd:function(b,a){if(b.wasDragged){$("newfolder").show();$("dropbase").hide()}}};DimpBase._folderDropConfig={hoverclass:"dragdrop",caption:function(e,f){var g=f.readAttribute("l"),c=e.readAttribute("ftype"),b=e.readAttribute("l"),a=DIMP.text.moveto;if(e==$("dropbase")){return a.replace(/%s/,g).replace(/%s/,DIMP.text.baselevel)}else{if(f.hasClassName("folder")){return(c!="special"&&!this.isSubfolder(f,e))?a.replace(/%s/,g).replace(/%s/,b):""}else{return c!="container"?a.replace(/%s/,this._dragCaption()).replace(/%s/,b):""}}}.bind(DimpBase),onDrop:DimpBase._folderDropHandler.bind(DimpBase)};document.observe("dom:loaded",function(){$("dimpLoading").hide();$("dimpPage").show();DimpCore.doAction("ListFolders",{},[],DimpBase._folderLoadCallback.bind(DimpBase));if(!DimpBase.delay_onload){DimpBase._onLoad()}if(DIMP.conf.is_ie6){document.observe("selectstart",Event.stop)}if(!DIMP.conf.search_all){DimpBase.sfiltersfolder.unset("sf_all
 ")}DimpBase.setPollFolders();document.observe("keydown",DimpBase._keydownHandler.bind(DimpBase));Event.observe(window,"resize",DimpBase._onResize.bind(DimpBase));if(DIMP.conf.is_ie6){var a=[],b;if(b=$("dimpbarActions")){a.push(b.select("SPAN"))}if(b=$("serviceActions")){a.push(b.select("LI.servicelink"))}if(b=$("applicationfolders")){a.push(b.select("UL LI"))}a.flatten().compact().each(function(c){c.observe("mouseover",c.addClassName.curry("over")).observe("mouseout",c.removeClassName.curry("over"))})}});if(DimpBase.delay_onload){Event.observe(window,"load",DimpBase._onLoad.bind(DimpBase))}DimpCore.onDoActionComplete=function(a){if(DimpBase.viewport&&a.response.viewport){DimpBase.viewport.ajaxResponse(a.response.viewport)}};DimpCore.addMouseEvents=DimpCore.addMouseEvents.wrap(DimpBase._addMouseEvents.bind(DimpBase));DimpCore.removeMouseEvents=DimpCore.removeMouseEvents.wrap(DimpBase._removeMouseEvents.bind(DimpBase));
+\ No newline at end of file
++/**
++ * DimpBase.js - Javascript used in the base DIMP page.
++ *
++ * $Horde: dimp/js/src/DimpBase.js,v 1.1.2.118 2009-05-20 18:27:51 slusarz Exp $
++ *
++ * Copyright 2005-2009 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.
++ */
++
++var DimpBase = {
++    // Vars used and defaulting to null/false:
++    //   filtertoggle, fl_visible, folder, folderswitch, fspecial, isvisible,
++    //   message_list_template, offset, pollpe, pp, searchobserve, uid,
++    //   viewport
++    bcache: $H(),
++    delay_onload: (!Prototype.Browser.Gecko && !Prototype.Browser.Opera),
++    lastrow: -1,
++    mo_sidebar: $H(),
++    pivotrow: -1,
++    ppcache: $H(),
++    ppfifo: [],
++    showPreview: DIMP.conf.preview_pref,
++
++    sfiltersfolder: $H({ sf_all: 'all', sf_current: 'current' }),
++    sfilters: $H({ sf_msgall: 'msgall', sf_from: 'from', sf_to: 'to', sf_subject: 'subject' }),
++
++    unseen_regex: new RegExp("(^|\\s)unseen(\\s|$)"),
++
++    // Message selection functions
++
++    // vs = (ViewPort_Selection) A ViewPort_Selection object.
++    // opts = (object) Boolean options [delay, right]
++    _select: function(vs, opts)
++    {
++        var d = vs.get('rownum');
++        if (d.size() == 1) {
++            this.lastrow = this.pivotrow = d.first();
++        }
++
++        this.toggleButtons();
++
++        if ($('previewPane').visible()) {
++            if (opts.right) {
++                this.clearPreviewPane();
++            } else {
++                if (opts.delay) {
++                    (this.bcache.get('initPP') || this.bcache.set('initPP', this.initPreviewPane.bind(this))).delay(opts.delay);
++                } else {
++                    this.initPreviewPane();
++                }
++            }
++        }
++    },
++
++    // vs = (ViewPort_Selection) A ViewPort_Selection object.
++    // opts = (object) Boolean options [right]
++    _deselect: function(vs, opts)
++    {
++        var sel = this.viewport.getSelected(),
++            count = sel.size();
++        if (!count) {
++            this.lastrow = this.pivotrow = -1;
++        }
++
++        this.toggleButtons();
++        if (opts.right || !count) {
++            this.clearPreviewPane();
++        } else if ((count == 1) && $('previewPane').visible()) {
++            this._loadPreview(sel.get('dataob').first());
++        }
++    },
++
++    // id = (string) DOM ID
++    // opts = (Object) Boolean options [ctrl, right, shift]
++    msgSelect: function(id, opts)
++    {
++        var bounds,
++            row = this.viewport.createSelection('domid', id),
++            rownum = row.get('rownum').first(),
++            sel = this.isSelected('domid', id),
++            selcount = this.selectedCount();
++
++        this.lastrow = rownum;
++
++        // Some browsers need to stop the mousedown event before it propogates
++        // down to the browser level in order to prevent text selection on
++        // drag/drop actions.  Clicking on a message should always lose focus
++        // from the search input, because the user may immediately start
++        // keyboard navigation after that. Thus, we need to ensure that a
++        // message click loses focus on the search input.
++        $('msgList_filter').blur();
++
++        if (opts.shift) {
++            if (selcount) {
++                if (!sel || selcount != 1) {
++                    bounds = [ rownum, this.pivotrow ];
++                    this.viewport.select($A($R(bounds.min(), bounds.max())), { range: true });
++                }
++                return;
++            }
++        } else if (opts.ctrl) {
++            this.pivotrow = rownum;
++            if (sel) {
++                this.viewport.deselect(row, { right: opts.right });
++                return;
++            } else if (opts.right || selcount) {
++                this.viewport.select(row, { add: true, right: opts.right });
++                return;
++            }
++        }
++
++        this.viewport.select(row, { right: opts.right });
++    },
++
++    selectAll: function()
++    {
++        this.viewport.select($A($R(1, this.viewport.getMetaData('total_rows'))), { range: true });
++    },
++
++    isSelected: function(format, data)
++    {
++        return this.viewport.getSelected().contains(format, data);
++    },
++
++    selectedCount: function()
++    {
++        return (this.viewport) ? this.viewport.getSelected().size() : 0;
++    },
++
++    resetSelected: function()
++    {
++        if (this.viewport) {
++            this.viewport.deselect(this.viewport.getSelected(), { clearall: true });
++        }
++        this.toggleButtons();
++        this.clearPreviewPane();
++    },
++
++    // absolute = Is num an absolute row number - from 1 -> page_size (true) -
++    //            or a relative change from the current selected value (false)
++    //            If no current selected value, the first message in the
++    //            current viewport is selected.
++    moveSelected: function(num, absolute)
++    {
++        var curr, curr_row, row, row_data, sel;
++
++        if (absolute) {
++            if (!this.viewport.getMetaData('total_rows')) {
++                return;
++            }
++            curr = num;
++        } else {
++            if (num == 0) {
++                return;
++            }
++
++            sel = this.viewport.getSelected();
++            switch (sel.size()) {
++            case 0:
++                curr = this.viewport.currentOffset();
++                curr += (num > 0) ? 1 : this.viewport.getPageSize('current');
++                break;
++
++            case 1:
++                curr_row = sel.get('dataob').first();
++                curr = curr_row.rownum + num;
++                break;
++
++            default:
++                sel = sel.get('rownum');
++                curr = (num > 0 ? sel.max() : sel.min()) + num;
++                break;
++            }
++            curr = (num > 0) ? Math.min(curr, this.viewport.getMetaData('total_rows')) : Math.max(curr, 1);
++        }
++
++        row = this.viewport.createSelection('rownum', curr);
++        if (row.size()) {
++            row_data = row.get('dataob').first();
++            if (!curr_row || row_data.imapuid != curr_row.imapuid) {
++                this.viewport.scrollTo(row_data.rownum);
++                this.viewport.select(row, { delay: 0.3 });
++            }
++        } else {
++            this.offset = curr;
++            this.viewport.requestContentRefresh(curr - 1);
++        }
++    },
++    // End message selection functions
++
++    go: function(loc, data)
++    {
++        var app, f, separator;
++
++        if (loc.startsWith('compose:')) {
++            return;
++        }
++
++        if (loc.startsWith('msg:')) {
++            separator = loc.indexOf(':', 4);
++            f = loc.substring(4, separator);
++            this.uid = loc.substring(separator + 1);
++            loc = 'folder:' + f;
++            // Now fall through to the 'folder:' check below.
++        }
++
++        if (loc.startsWith('folder:')) {
++            f = loc.substring(7);
++            if (this.folder != f || !$('dimpmain_folder').visible()) {
++                this.highlightSidebar(this.getFolderId(f));
++                if (!$('dimpmain_folder').visible()) {
++                    $('dimpmain_portal').hide();
++                    $('dimpmain_folder').show();
++                }
++                // This catches the refresh case - no need to re-add to history
++                if (!Object.isUndefined(this.folder)) {
++                    this._addHistory(loc);
++                }
++            }
++            this.loadFolder(f);
++            return;
++        }
++
++        this.folder = null;
++        $('dimpmain_folder').hide();
++        $('dimpmain_portal').update(DIMP.text.loading).show();
++
++        if (loc.startsWith('app:')) {
++            app = loc.substr(4);
++            if (app == 'imp' || app == 'dimp') {
++                this.go('folder:INBOX');
++                return;
++            }
++            this.highlightSidebar('app' + app);
++            this._addHistory(loc, data);
++            if (data) {
++                this.iframeContent(loc, data);
++            } else if (DIMP.conf.app_urls[app]) {
++                this.iframeContent(loc, DIMP.conf.app_urls[app]);
++            }
++            return;
++        }
++
++        switch (loc) {
++        case 'portal':
++            this.highlightSidebar('appportal');
++            this._addHistory(loc);
++            DimpCore.setTitle(DIMP.text.portal);
++            DimpCore.doAction('ShowPortal', {}, [], this.bcache.get('portalC') || this.bcache.set('portalC', this._portalCallback.bind(this)));
++            break;
++
++        case 'options':
++            this.highlightSidebar('appoptions');
++            this._addHistory(loc);
++            DimpCore.setTitle(DIMP.text.prefs);
++            this.iframeContent(loc, DIMP.conf.prefs_url);
++            break;
++        }
++    },
++
++    _addHistory: function(loc, data)
++    {
++        if (Horde.dhtmlHistory.getCurrentLocation() != loc) {
++            Horde.dhtmlHistory.add(loc, data);
++        }
++    },
++
++    highlightSidebar: function(id)
++    {
++        // Folder bar may not be fully loaded yet.
++        if ($('foldersLoading').visible()) {
++            this.highlightSidebar.bind(this, id).defer();
++            return;
++        }
++
++        $('sidebarPanel').select('.on').invoke('removeClassName', 'on');
++
++        var elt = $(id);
++        if (!elt) {
++            return;
++        }
++        if (!elt.match('LI')) {
++            elt = elt.up();
++            if (!elt) {
++                return;
++            }
++        }
++        elt.addClassName('on');
++
++        // Make sure all subfolders are expanded
++        elt.ancestors().find(function(n) {
++            if (n.hasClassName('subfolders')) {
++                this._toggleSubFolder(n.id.substring(3), 'exp');
++            } else {
++                return (n.id == 'foldersSidebar');
++            }
++        }, this);
++    },
++
++    iframeContent: function(name, loc)
++    {
++        if (name === null) {
++            name = loc;
++        }
++
++        var container = $('dimpmain_portal'), iframe;
++        if (!container) {
++            DimpCore.showNotifications([ { type: 'horde.error', message: 'Bad portal!' } ]);
++            return;
++        }
++
++        iframe = new Element('IFRAME', { id: 'iframe' + name, className: 'iframe', frameBorder: 0, src: loc });
++        this._resizeIE6Iframe(iframe);
++
++        // Hide menu in prefs pages.
++        if (name == 'options') {
++            iframe.observe('load', function() { $('iframeoptions').contentWindow.document.getElementById('menu').style.display = 'none'; });
++        }
++
++        container.insert(iframe);
++    },
++
++    // r = ViewPort row data
++    msgWindow: function(r)
++    {
++        this.updateUnseenUID(r, 0);
++        var url = DIMP.conf.message_url;
++        url += (url.include('?') ? '&' : '?') +
++               $H({ folder: r.view,
++                    uid: r.imapuid }).toQueryString();
++        DimpCore.popupWindow(url, 'msgview' + r.view + r.imapuid);
++    },
++
++    composeMailbox: function(type)
++    {
++        var sel = this.viewport.getSelected();
++        if (!sel.size()) {
++            return;
++        }
++        sel.get('dataob').each(function(s) {
++            DimpCore.compose(type, { folder: s.view, uid: s.imapuid });
++        });
++    },
++
++    loadFolder: function(f, background)
++    {
++        if (!this.viewport) {
++            this._createViewPort();
++        }
++
++        if (!background) {
++            this.resetSelected();
++
++            if (this.folder == f) {
++                this.searchfilterClear(false);
++                return;
++            }
++
++            this.searchfilterClear(true);
++            $('folderName').update(DIMP.text.loading);
++            $('msgHeader').update();
++            this.folderswitch = true;
++            this.folder = f;
++        }
++
++        this.viewport.loadView(f, { folder: f }, this.uid ? { imapuid: DimpCore.toUIDString(this.uid, f) } : null, background);
++    },
++
++    _createViewPort: function()
++    {
++        var mf = $('msgList_filter'),
++            // No need to cache - this function only called once.
++            settitle = this.setMessageListTitle.bind(this);
++
++        this.viewport = new ViewPort({
++            content_container: 'msgList',
++            empty_container: 'msgList_empty',
++            error_container: 'msgList_error',
++            fetch_action: 'ListMessages',
++            template: this.message_list_template,
++            buffer_pages: DIMP.conf.buffer_pages,
++            limit_factor: DIMP.conf.limit_factor,
++            viewport_wait: DIMP.conf.viewport_wait,
++            show_split_pane: this.showPreview,
++            split_pane: 'previewPane',
++            splitbar: 'splitBar',
++            content_class: 'msglist',
++            row_class: 'msgRow',
++            selected_class: 'selectedRow',
++            ajaxRequest: DimpCore.doAction.bind(DimpCore),
++            norows: true,
++            onScrollIdle: settitle,
++            onSlide: settitle,
++            onViewChange: function() {
++                DimpCore.addGC(this.viewport.visibleRows());
++            }.bind(this),
++            onContent: function(rows) {
++                var mf, search,
++                    thread = ((this.viewport.getMetaData('sortby') == DIMP.conf.sortthread) && this.viewport.getMetaData('thread'));
++                if (this.viewport.isFiltering()) {
++                    search = this.sfilters.get(this._getSearchfilterField()).capitalize();
++                    mf = new RegExp("(" + $F('msgList_filter') + ")", "i");
++                }
++                rows.get('dataob').each(function(row) {
++                    var elt, tmp, u,
++                        r = $(row.domid);
++                    // Add thread graphics
++                    if (thread && thread[row.imapuid]) {
++                        elt = r.down('.msgSubject');
++                        tmp = elt.cloneNode(false);
++                        u = thread[row.imapuid];
++                        $R(0, u.length, true).each(function(i) {
++                            tmp.insert($($('thread_img_' + u.charAt(i)).cloneNode(false)).writeAttribute('id', ''));
++                        });
++                        elt.replace(tmp.insert(elt.getText().escapeHTML()));
++                    }
++                    // Add attachment graphics
++                    if (row.atc) {
++                        r.down('.msgSize').insert({ top: $($('atc_img_' + row.atc).cloneNode(false)).writeAttribute('id', '') });
++                    }
++
++                    // Add context menu.
++                    DimpCore.addMouseEvents({ id: row.domid, type: row.menutype });
++
++                    // Highlight search terms
++                    if (search == 'From' || search == 'Subject') {
++                        elt = r.down('.msg' + search);
++                        elt.update(elt.getText().escapeHTML().gsub(mf, '<span class="searchMatch">#{1}</span>'));
++                    }
++                }, this);
++                this.setMessageListTitle();
++            }.bind(this),
++            onComplete: function() {
++                var row, ssc,
++                    l = this.viewport.getMetaData('label');
++
++                if (this.uid) {
++                    row = this.viewport.getViewportSelection().search({ imapuid: { equal: [ this.uid ] }, view: { equal: [ this.folder ] } });
++                    if (row.size()) {
++                        this.viewport.scrollTo(row.get('rownum').first());
++                        this.viewport.select(row);
++                    }
++                } else if (this.offset) {
++                    this.viewport.select(this.viewport.createSelection('rownum', this.offset));
++                }
++                this.offset = this.uid = null;
++
++                // 'label' will not be set if there has been an error
++                // retrieving data from the server.
++                l = this.viewport.getMetaData('label');
++                if (l) {
++                    $('folderName').update(l);
++                }
++
++                if (this.folderswitch) {
++                    this.folderswitch = false;
++                    if (this.folder == DIMP.conf.spam_folder) {
++                        if (!DIMP.conf.spam_spamfolder &&
++                            DimpCore.buttons.indexOf('button_spam') != -1) {
++                            [ $('button_spam').up(), $('ctx_message_spam') ].invoke('hide');
++                        }
++                        if (DimpCore.buttons.indexOf('button_ham') != -1) {
++                            [ $('button_ham').up(), $('ctx_message_ham') ].invoke('show');
++                        }
++                    } else {
++                        if (DimpCore.buttons.indexOf('button_spam') != -1) {
++                            [ $('button_spam').up(), $('ctx_message_spam') ].invoke('show');
++                        }
++                        if (DimpCore.buttons.indexOf('button_ham') != -1) {
++                            if (DIMP.conf.ham_spamfolder) {
++                                [ $('button_ham').up(), $('ctx_message_ham') ].invoke('hide');
++                            } else {
++                                [ $('button_ham').up(), $('ctx_message_ham') ].invoke('show');
++                            }
++                        }
++                    }
++                } else if (this.filtertoggle) {
++                    if (this.filtertoggle == 1 &&
++                        this.viewport.getMetaData('sortby') == DIMP.conf.sortthread) {
++                        ssc = DIMP.conf.sortdate;
++                    }
++                    this.filtertoggle = 0;
++                }
++
++                this.setSortColumns(ssc);
++
++                if (this.viewport.isFiltering()) {
++                    this.resetSelected();
++                    this.updateTitle();
++                } else {
++                    this.setFolderLabel(this.folder, this.viewport.getMetaData('unseen'));
++                }
++            }.bind(this),
++            onFetch: this.msgListLoading.bind(this, true),
++            onEndFetch: this.msgListLoading.bind(this, false),
++            onWait: function() {
++                if ($('dimpmain_folder').visible()) {
++                    DimpCore.showNotifications([ { type: 'horde.warning', message: DIMP.text.listmsg_wait } ]);
++                }
++            },
++            onFail: function() {
++                if ($('dimpmain_folder').visible()) {
++                    DimpCore.showNotifications([ { type: 'horde.error', message: DIMP.text.listmsg_timeout } ]);
++                }
++                this.msgListLoading(false);
++            }.bind(this),
++            onFirstContent: function() {
++                this.clearPreviewPane();
++                $('msgList').observe('dblclick', this._handleMsgListDblclick.bindAsEventListener(this));
++            }.bind(this),
++            onClearRows: function(r) {
++                r.each(function(row) {
++                    var c = $(row).down('div.msCheck');
++                    if (c) {
++                        DimpCore.addGC(c);
++                    }
++                    if (row.id) {
++                        DimpCore.removeMouseEvents(row);
++                    }
++                });
++            },
++            onBeforeResize: function() {
++                var sel = this.viewport.getSelected();
++                this.isvisible = (sel.size() == 1) && (this.viewport.isVisible(sel.get('rownum').first()) == 0);
++            }.bind(this),
++            onAfterResize: function() {
++                if (this.isvisible) {
++                    this.viewport.scrollTo(this.viewport.getSelected().get('rownum').first());
++                }
++            }.bind(this),
++            selectCallback: this._select.bind(this),
++            deselectCallback: this._deselect.bind(this)
++        });
++
++        // If starting in no preview mode, need to set the no preview class
++        if (!this.showPreview) {
++            $('msgList').addClassName('msglistNoPreview');
++        }
++
++        // Set up viewport filter events.
++        this.viewport.addFilter('ListMessages', this._addSearchfilterParams.bind(this));
++        mf.observe('keyup', this._searchfilterOnKeyup.bind(this));
++        mf.observe('focus', this._searchfilterOnFocus.bind(this));
++        mf.observe('blur', this._searchfilterOnBlur.bind(this));
++        mf.addClassName('msgFilterDefault');
++    },
++
++    _addMouseEvents: function(parentfunc, p)
++    {
++        var elt;
++
++        switch (p.type) {
++        case 'draft':
++        case 'message':
++            new Drag(p.id, this._msgDragConfig);
++            elt = $(p.id).down('div.msCheck');
++            if (elt.visible()) {
++                elt.observe('mousedown', this.bcache.get('handleMLC') || this.bcache.set('handleMLC', this._handleMsgListCheckbox.bindAsEventListener(this)));
++                elt.observe('contextmenu', Event.stop);
++            }
++            break;
++
++        case 'container':
++        case 'folder':
++            new Drag(p.id, this._folderDragConfig);
++            break;
++
++        case 'special':
++            // For purposes of the contextmenu, treat special folders
++            // like regular folders.
++            p.type = 'folder';
++            break;
++        }
++        p.onShow = this.bcache.get('onMS') || this.bcache.set('onMS', this._onMenuShow.bind(this));
++        parentfunc(p);
++    },
++
++    _removeMouseEvents: function(parentfunc, elt)
++    {
++        var d, id = $(elt).readAttribute('id');
++        if (id && (d = DragDrop.Drags.get_drag(id))) {
++            d.destroy();
++        }
++        parentfunc(elt);
++    },
++
++    _onMenuShow: function(ctx)
++    {
++        var elts, folder, ob, sel;
++
++        switch (ctx.ctx) {
++        case 'ctx_folder':
++            elts = $('ctx_folder_create', 'ctx_folder_rename', 'ctx_folder_delete');
++            folder = DimpCore.DMenu.element();
++            if (folder.readAttribute('mbox') == 'INBOX') {
++                elts.invoke('hide');
++            } else if (DIMP.conf.fixed_folders.indexOf(folder.readAttribute('mbox')) != -1) {
++                elts.shift();
++                elts.invoke('hide');
++            } else {
++                elts.invoke('show');
++            }
++
++            if (folder.hasAttribute('u')) {
++                $('ctx_folder_poll').hide();
++                $('ctx_folder_nopoll').show();
++            } else {
++                $('ctx_folder_poll').show();
++                $('ctx_folder_nopoll').hide();
++            }
++            break;
++
++        case 'ctx_message':
++            [ $('ctx_message_reply_list') ].invoke( this.viewport.createSelection('domid', ctx.id).get('dataob').first().listmsg ? 'show' : 'hide');
++            break;
++
++        case 'ctx_reply':
++            sel = this.viewport.getSelected();
++            if (sel.size() == 1) {
++                ob = sel.get('dataob').first();
++            }
++            [ $('ctx_reply_reply_list') ].invoke(ob && ob.listmsg ? 'show' : 'hide');
++            break;
++
++        case 'ctx_otheractions':
++            $('oa_seen', 'oa_unseen', 'oa_flagged', 'oa_clear', 'oa_sep1', 'oa_blacklist', 'oa_whitelist', 'oa_sep2', 'oa_undelete').compact().invoke(this.viewport.getSelected().size() ? 'show' : 'hide');
++            break;
++        }
++        return true;
++    },
++
++    _onResize: function()
++    {
++        if (this.viewport) {
++            this.viewport.onResize();
++        }
++        this._resizeIE6();
++    },
++
++    _handleMsgListDblclick: function(e)
++    {
++        var elt = this._getMsgRow(e);
++        if (!elt) {
++            return;
++        }
++        var row = this.viewport.createSelection('domid', elt.id).get('dataob').first();
++        row.draft ? DimpCore.compose('resume', { folder: row.view, uid: row.imapuid }) : this.msgWindow(row);
++        e.stop();
++    },
++
++    _handleMsgListCheckbox: function(e)
++    {
++        var elt = this._getMsgRow(e);
++        if (!elt) {
++            return;
++        }
++        this.msgSelect(elt.readAttribute('id'), { ctrl: true, right: true });
++        e.stop();
++    },
++
++    _getMsgRow: function(e)
++    {
++        e = e.element();
++        if (e && !e.hasClassName('msgRow')) {
++            e = e.up('.msgRow');
++        }
++        return e;
++    },
++
++    updateTitle: function()
++    {
++        var elt, label, unseen;
++        if (this.viewport.isFiltering()) {
++            label = DIMP.text.search + ' :: ' + this.viewport.getMetaData('total_rows') + ' ' + DIMP.text.resfound;
++        } else {
++            elt = $(this.getFolderId(this.folder));
++            if (elt) {
++                unseen = elt.readAttribute('u');
++                label = elt.readAttribute('l');
++                if (unseen > 0) {
++                    label += ' (' + unseen + ')';
++                }
++            } else {
++                label = this.viewport.getMetaData('label');
++            }
++        }
++        DimpCore.setTitle(label);
++    },
++
++    sort: function(e)
++    {
++        // Don't change sort if we are past the sortlimit
++        if (this.viewport.getMetaData('sortlimit')) {
++            return;
++        }
++
++        var s, sortby,
++            elt = e.element();
++        if (!elt.hasAttribute('sortby')) {
++            elt = elt.up('[sortby]');
++            if (!elt) {
++                return;
++            }
++        }
++        sortby = parseInt(elt.readAttribute('sortby'), 10);
++
++        if (sortby == this.viewport.getMetaData('sortby')) {
++            s = { sortdir: (this.viewport.getMetaData('sortdir') ? 0 : 1) };
++            this.viewport.setMetaData({ sortdir: s.sortdir });
++        } else {
++            s = { sortby: sortby };
++            this.viewport.setMetaData({ sortby: s.sortby });
++        }
++        this.setSortColumns(sortby);
++        this.viewport.reload(s);
++    },
++
++    setSortColumns: function(sortby)
++    {
++        var tmp,
++            m = $('msglistHeader');
++
++        if (Object.isUndefined(sortby)) {
++            sortby = this.viewport.getMetaData('sortby');
++        }
++
++        tmp = m.down('small[sortby=' + sortby + ']');
++        if (tmp && tmp.up().visible()) {
++           tmp.up(1).childElements().invoke('toggle');
++        }
++
++        tmp = m.down('div.msgFrom a');
++        if ((this.viewport.isFiltering() && this.fspecial) ||
++            this.viewport.getMetaData('special')) {
++            tmp.hide().next().show();
++        } else {
++            tmp.show().next().hide();
++        }
++
++        tmp = m.down('div.msgSubject a');
++        if (this.viewport.isFiltering() ||
++            this.viewport.getMetaData('nothread') ||
++            this.viewport.getMetaData('sortlimit')) {
++            tmp.show().next().hide();
++            tmp.down().hide();
++        } else {
++            tmp.down().show();
++        }
++
++        m.childElements().invoke('removeClassName', 'sortup').invoke('removeClassName', 'sortdown');
++        m.down('div a[sortby=' + sortby + ']').up().addClassName(this.viewport.getMetaData('sortdir') ? 'sortup' : 'sortdown');
++    },
++
++    // Preview pane functions
++    togglePreviewPane: function()
++    {
++        this.showPreview = !this.showPreview;
++        $('previewtoggle').setText(this.showPreview ? DIMP.text.hide_preview : DIMP.text.show_preview);
++        [ $('msgList') ].invoke(this.showPreview ? 'removeClassName' : 'addClassName', 'msglistNoPreview');
++        new Ajax.Request(DimpCore.addSID(DIMP.conf.URI_PREFS), { parameters: { app: 'dimp', pref: 'show_preview', value: this.showPreview ? 1 : 0 } });
++        this.viewport.showSplitPane(this.showPreview);
++        if (this.showPreview) {
++            this.initPreviewPane();
++        }
++        this.updateTitle();
++    },
++
++    _loadPreview: function(data)
++    {
++        var pp = $('previewPane'), pp_offset;
++        if (!pp.visible()) {
++            return;
++        }
++        if (this.pp &&
++            this.pp == data) {
++            return;
++        }
++        this.pp = data;
++
++        if (this.ppfifo.indexOf(data.vp_id) != -1) {
++            return this._loadPreviewCallback(this.ppcache.get(data.vp_id));
++        }
++
++        pp_offset = pp.positionedOffset();
++        $('msgLoading').setStyle({ position: 'absolute', top: (pp_offset.top + 10) + 'px', left: (pp_offset.left + 10) + 'px' }).show();
++
++        DimpCore.doAction('ShowPreview', {}, DimpCore.toUIDArray(this.viewport.createSelection('dataob', data)), this.bcache.get('loadPC') || this.bcache.set('loadPC', this._loadPreviewCallback.bind(this)));
++    },
++
++    _loadPreviewCallback: function(resp)
++    {
++        var row, search, tmp, tmp2,
++            pm = $('previewMsg'),
++            r = resp.response;
++
++        if (!r.error) {
++            search = this.viewport.getViewportSelection(r.view).search({ vp_id: { equal: [ r.uid ] } });
++            if (search.size()) {
++                row = search.get('dataob').first();
++                this.updateUnseenUID(row, 0);
++            }
++        }
++
++        if (this.pp &&
++            this.pp.vp_id != r.uid) {
++            return;
++        }
++
++        if (r.error || this.viewport.getSelected().size() != 1) {
++            if (r.error) {
++                DimpCore.showNotifications([ { type: r.errortype, message: r.error } ]);
++            }
++            this.clearPreviewPane();
++            return;
++        }
++
++        // Store in cache.
++        this._expirePPCache([ r.uid ]);
++        this.ppcache.set(r.uid, resp);
++        this.ppfifo.push(r.uid);
++
++        DimpCore.removeAddressLinks(pm);
++
++        DIMP.conf.msg_index = r.index;
++        DIMP.conf.msg_folder = r.folder;
++        DIMP.conf.msg_source_link = r.source_link;
++
++        // Add subject/priority
++        tmp = pm.select('.subject');
++        tmp.invoke('update', r.subject);
++        switch (r.priority) {
++        case 'high':
++        case 'low':
++            tmp.invoke('insert', { top: $($(r.priority + '_priority_img').cloneNode(false)).writeAttribute('id', false) });
++            break;
++        }
++
++        // Add from/date
++        pm.select('.from').invoke('update', r.from);
++        $('msgHeadersColl').select('.date').invoke('update', r.minidate);
++        $('msgHeaderDate').select('.date').invoke('update', r.fulldate);
++
++        // Add to/cc
++        [ 'to', 'cc' ].each(function(a) {
++            if (r[a]) {
++                pm.select('.' + a).invoke('update', r[a]);
++            }
++            [ $('msgHeader' + a.capitalize()) ].invoke(r[a] ? 'show' : 'hide');
++        });
++
++        // Add attachment information
++        $('msgHeadersColl').select('.attachmentImage').invoke(r.atc_label ? 'show' : 'hide');
++        if (r.atc_label) {
++            tmp = $('msgAtc').show().down('.label');
++            tmp2 = $('partlist');
++            tmp2.hide().previous().update(r.atc_label + ' ' + r.atc_download);
++            if (r.atc_list) {
++                $('partlist_col').show();
++                $('partlist_exp').hide();
++                tmp.down().hide().next().show();
++                tmp2.update(r.atc_list);
++            } else {
++                tmp.down().show().next().hide();
++            }
++        } else {
++            $('msgAtc').hide();
++        }
++
++        $('msgBody').down().update(r.msgtext);
++        $('msgLoading', 'previewInfo').invoke('hide');
++        $('previewPane').scrollTop = 0;
++        pm.show();
++
++        if (r.js) {
++            eval(r.js.join(';'));
++        }
++        DimpCore.buildAddressLinks(pm);
++        this._addHistory('msg:' + row.view + ':' + row.imapuid);
++    },
++
++    initPreviewPane: function()
++    {
++        var sel = this.viewport.getSelected();
++        if (sel.size() != 1) {
++            this.clearPreviewPane();
++        } else {
++            this._loadPreview(sel.get('dataob').first());
++        }
++    },
++
++    clearPreviewPane: function()
++    {
++        $('msgLoading', 'previewMsg').invoke('hide');
++        $('previewInfo').show();
++        this.pp = null;
++    },
++
++    _expirePPCache: function(ids)
++    {
++        this.ppfifo = this.ppfifo.without(ids);
++        ids.each(this.ppcache.unset.bind(this.ppcache));
++        // Preview pane cache size is 20 entries. Given that a reasonable guess
++        // of an average e-mail size is 10 KB (including headers), also make
++        // an estimate that the JSON data size will be approx. 10 KB. 200 KB
++        // should be a fairly safe caching value for any recent browser.
++        if (this.ppfifo.size() > 20) {
++            this.ppcache.unset(this.ppfifo.shift());
++        }
++    },
++
++    // Labeling functions
++    updateUnseenUID: function(r, setflag)
++    {
++        var sel, unseenset,
++            unseen = 0;
++        if (!r.bg) {
++            return false;
++        }
++        unseenset = r.bg.match(this.unseen_regex);
++        if ((setflag && unseenset) || (!setflag && !unseenset)) {
++            return false;
++        }
++
++        sel = this.viewport.createSelection('dataob', r);
++        if (setflag) {
++            this.viewport.updateFlag(sel, 'unseen', true);
++            ++unseen;
++        } else {
++            this.viewport.updateFlag(sel, 'unseen', false);
++            --unseen;
++        }
++
++        return this.updateUnseenStatus(r.view, unseen);
++    },
++
++    updateUnseenStatus: function(mbox, change)
++    {
++        if (change == 0) {
++            return false;
++        }
++        var unseen = parseInt($(this.getFolderId(mbox)).readAttribute('u')) + change;
++        this.viewport.setMetaData({ unseen: unseen });
++        this.setFolderLabel(mbox, unseen);
++        return true;
++    },
++
++    setMessageListTitle: function()
++    {
++        var offset,
++            rows = this.viewport.getMetaData('total_rows');
++        if (rows > 0) {
++            offset = this.viewport.currentOffset();
++            $('msgHeader').update(DIMP.text.messages + ' ' + (offset + 1) + ' - ' + (Math.min(offset + this.viewport.getPageSize(), rows)) + ' ' + DIMP.text.of + ' ' + rows);
++        } else {
++            $('msgHeader').update(DIMP.text.nomessages);
++        }
++    },
++
++    setFolderLabel: function(f, unseen)
++    {
++        var elt, fid = this.getFolderId(f);
++        elt = $(fid);
++        if (!elt || !elt.hasAttribute('u')) {
++            return;
++        }
++
++        unseen = parseInt(unseen);
++        elt.writeAttribute('u', unseen);
++
++        if (f == 'INBOX' && window.fluid) {
++            window.fluid.setDockBadge(unseen ? unseen : '');
++        }
++
++        $(fid + '_label').update((unseen > 0) ?
++            new Element('STRONG').insert(elt.readAttribute('l')).insert(' ').insert(new Element('SPAN', { className: 'count', dir: 'ltr' }).insert('(' + unseen + ')')) :
++            elt.readAttribute('l'));
++
++        if (this.folder == f) {
++            this.updateTitle();
++        }
++    },
++
++    getFolderId: function(f)
++    {
++        return 'fld' + decodeURIComponent(f).replace(/_/g,'__').replace(/\W/g, '_');
++    },
++
++    getSubFolderId: function(f)
++    {
++        return 'sub' + f;
++    },
++
++    /* Folder list updates. */
++    pollFolders: function()
++    {
++        // Reset poll folder counter.
++        this.setPollFolders();
++        var args = {};
++        if (this.folder && $('dimpmain_folder').visible()) {
++            args = this.viewport.addRequestParams({});
++        }
++        $('button_checkmail').setText('[' + DIMP.text.check + ']');
++        DimpCore.doAction('PollFolders', args, [], this.bcache.get('pollFC') || this.bcache.set('pollFC', this._pollFoldersCallback.bind(this)));
++    },
++
++    _pollFoldersCallback: function(r)
++    {
++        r = r.response;
++        if (r.poll) {
++            $H(r.poll).each(function(u) {
++                this.setFolderLabel(u.key, u.value);
++                if (this.viewport) {
++                    this.viewport.setMetaData({ unseen: u.value }, u.key);
++                }
++            }, this);
++        }
++        if (r.quota) {
++            $('quota').update(r.quota);
++        }
++        $('button_checkmail').setText(DIMP.text.getmail);
++    },
++
++    setPollFolders: function()
++    {
++        if (DIMP.conf.refresh_time) {
++            if (this.pollPE) {
++                this.pollPE.stop();
++            }
++            // Don't cache - this code is only run once.
++            this.pollPE = new PeriodicalExecuter(this.pollFolders.bind(this), DIMP.conf.refresh_time);
++        }
++    },
++
++    _portalCallback: function(r)
++    {
++        if (r.response.linkTags) {
++            var head = $$('HEAD').first();
++            r.response.linkTags.each(function(newLink) {
++                var link = new Element('LINK', { type: 'text/css', rel: 'stylesheet', href: newLink.href });
++                if (newLink.media) {
++                    link.media = newLink.media;
++                }
++                head.insert(link);
++            });
++        }
++        $('dimpmain_portal').update(r.response.portal);
++
++        /* Link portal block headers to the application. */
++        $('dimpmain_portal').select('h1.header a').each(this.bcache.get('portalClkLink') || this.bcache.set('portalClkLink', function(d) {
++            d.observe('click', function(e, d) {
++                this.go('app:' + d.readAttribute('app'));
++                e.stop();
++            }.bindAsEventListener(this, d));
++        }.bind(this)));
++    },
++
++    /* Search filter functions. */
++    _searchfilterOnKeyup: function()
++    {
++        if (this.searchobserve) {
++            clearTimeout(this.searchobserve);
++        }
++        this.searchobserve = (this.bcache.get('searchfilterR') || this.bcache.set('searchfilterR', this.searchfilterRun.bind(this))).delay(0.5);
++    },
++
++    searchfilterRun: function()
++    {
++        if (!this.viewport.isFiltering()) {
++            this.filtertoggle = 1;
++            this.fspecial = this.viewport.getMetaData('special');
++        }
++        this.viewport.runFilter($F('msgList_filter'));
++    },
++
++    _searchfilterOnFocus: function()
++    {
++        var q = $('qoptions');
++
++        if ($('msgList_filter').hasClassName('msgFilterDefault')) {
++            this._setFilterText(false);
++        }
++
++        if (!q.visible()) {
++            $('sf_current').update(this.viewport.getMetaData('label'));
++            this._setSearchfilterParams(this.viewport.getMetaData('special') ? 'to' : 'from', 'msg');
++            this._setSearchfilterParams('current', 'folder');
++            q.show();
++            this.viewport.onResize();
++        }
++    },
++
++    _searchfilterOnBlur: function()
++    {
++        if (!$F('msgList_filter')) {
++            this._setFilterText(true);
++        }
++    },
++
++    // reset = (boolean) TODO
++    searchfilterClear: function(reset)
++    {
++        if (!$('qoptions').visible()) {
++            return;
++        }
++        if (this.searchobserve) {
++            clearTimeout(this.searchobserve);
++            this.searchobserve = null;
++        }
++        this._setFilterText(true);
++        $('qoptions').hide();
++        this.filtertoggle = 2;
++        this.resetSelected();
++        this.viewport.onResize(reset);
++        this.viewport.stopFilter(reset);
++    },
++
++    // d = (boolean) Deactivate filter input?
++    _setFilterText: function(d)
++    {
++        var mf = $('msgList_filter');
++        if (d) {
++            mf.setValue(DIMP.text.search);
++            mf.addClassName('msgFilterDefault');
++        } else {
++            mf.setValue('');
++            mf.removeClassName('msgFilterDefault');
++        }
++    },
++
++    // type = 'folder' or 'msg'
++    _setSearchfilterParams: function(id, type)
++    {
++        var c = (type == 'folder') ? this.sfiltersfolder : this.sfilters;
++        c.keys().each(function(i) {
++            $(i).writeAttribute('className', (id == c.get(i)) ? 'qselected' : '');
++        });
++    },
++
++    updateSearchfilter: function(id, type)
++    {
++        this._setSearchfilterParams(id, type);
++        if ($F('msgList_filter')) {
++            this.viewport.runFilter();
++        }
++    },
++
++    _addSearchfilterParams: function()
++    {
++        var sf = this.sfiltersfolder.keys().find(function(s) {
++                return $(s).hasClassName('qselected');
++            });
++        return { searchfolder: this.sfiltersfolder.get(sf), searchmsg: this.sfilters.get(this._getSearchfilterField()) };
++    },
++
++    _getSearchfilterField: function()
++    {
++        return this.sfilters.keys().find(function(s) {
++            return $(s).hasClassName('qselected');
++        });
++    },
++
++    /* Enable/Disable DIMP action buttons as needed. */
++    toggleButtons: function()
++    {
++        var disable = (this.selectedCount() == 0);
++        DimpCore.buttons.each(function(b) {
++            var elt = $(b);
++            if (elt) {
++                [ elt.up() ].invoke(disable ? 'addClassName' : 'removeClassName', 'disabled');
++                DimpCore.DMenu.disable(b + '_img', true, disable);
++            }
++        });
++    },
++
++    /* Drag/Drop handler. */
++    _folderDropHandler: function(drop, drag)
++    {
++        var dropbase, sel, uids,
++            foldername = drop.readAttribute('mbox'),
++            ftype = drop.readAttribute('ftype');
++
++        if (drag.hasClassName('folder')) {
++            dropbase = (drop == $('dropbase'));
++            if (dropbase ||
++                (ftype != 'special' && !this.isSubfolder(drag, drop))) {
++                DimpCore.doAction('RenameFolder', { old_name: drag.readAttribute('mbox'), new_parent: dropbase ? '' : foldername, new_name: drag.readAttribute('l') }, [], this.bcache.get('folderC') || this.bcache.set('folderC', this._folderCallback.bind(this)));
++            }
++        } else if (ftype != 'container') {
++            sel = this.viewport.getSelected();
++
++            if (sel.size()) {
++                // Dragging multiple selected messages.
++                uids = sel;
++            } else if (drag.readAttribute('mbox') != foldername) {
++                // Dragging a single unselected message.
++                uids = this.viewport.createSelection('domid', drag.id);
++            }
++
++            // Don't allow drag/drop to the current folder.
++            if (uids.size() && this.folder != foldername) {
++                this.viewport.updateFlag(uids, 'deletedmsg', true);
++                DimpCore.doAction('MoveMessage', this.viewport.addRequestParams({ tofld: foldername }), DimpCore.toUIDArray(uids), this.bcache.get('deleteC') || this.bcache.set('deleteC', this._deleteCallback.bind(this)));
++            }
++        }
++    },
++
++    _dragCaption: function()
++    {
++        var cnt = this.selectedCount();
++        return cnt + ' ' + (cnt == 1 ? DIMP.text.message : DIMP.text.messages);
++    },
++
++    /* Keydown event handler */
++    _keydownHandler: function(e)
++    {
++        // Only catch keyboard shortcuts in message list view. Disable catching
++        // when in form elements or the RedBox overlay is visible.
++        if (!$('dimpmain_folder').visible() ||
++            e.findElement('FORM') ||
++            RedBox.overlayVisible()) {
++            return;
++        }
++
++        var co, ps, r, row, rowoff,
++            kc = e.keyCode || e.charCode,
++            sel = this.viewport.getSelected();
++
++        switch (kc) {
++        case Event.KEY_DELETE:
++        case Event.KEY_BACKSPACE:
++            r = sel.get('dataob');
++            if (e.shiftKey) {
++                this.moveSelected((r.last().rownum == this.viewport.getMetaData('total_rows')) ? (r.first().rownum - 1) : (r.last().rownum + 1), true);
++            }
++            this.flag('deleted', r);
++            e.stop();
++            break;
++
++        case Event.KEY_UP:
++        case Event.KEY_DOWN:
++            if (e.shiftKey && this.lastrow != -1) {
++                row = this.viewport.createSelection('rownum', this.lastrow + ((kc == Event.KEY_UP) ? -1 : 1));
++                if (row.size()) {
++                    row = row.get('dataob').first();
++                    this.viewport.scrollTo(row.rownum);
++                    this.msgSelect(row.domid, { shift: true });
++                }
++            } else {
++                this.moveSelected(kc == Event.KEY_UP ? -1 : 1);
++            }
++            e.stop();
++            break;
++
++        case Event.KEY_PAGEUP:
++        case Event.KEY_PAGEDOWN:
++            if (!e.ctrlKey && !e.shiftKey && !e.altKey && !e.metaKey) {
++                ps = this.viewport.getPageSize() - 1;
++                move = ps * (kc == Event.KEY_PAGEUP ? -1 : 1);
++                if (sel.size() == 1) {
++                    co = this.viewport.currentOffset();
++                    rowoff = sel.get('rownum').first() - 1;
++                    switch (kc) {
++                    case Event.KEY_PAGEUP:
++                        if (co != rowoff) {
++                            move = co - rowoff;
++                        }
++                        break;
++
++                    case Event.KEY_PAGEDOWN:
++                        if ((co + ps) != rowoff) {
++                            move = co + ps - rowoff;
++                        }
++                        break;
++                    }
++                }
++                this.moveSelected(move);
++                e.stop();
++            }
++            break;
++
++        case Event.KEY_HOME:
++        case Event.KEY_END:
++            this.moveSelected(kc == Event.KEY_HOME ? 1 : this.viewport.getMetaData('total_rows'), true);
++            e.stop();
++            break;
++
++        case Event.KEY_RETURN:
++            if (!e.element().match('input')) {
++                // Popup message window if single message is selected.
++                if (sel.size() == 1) {
++                    this.msgWindow(sel.get('dataob').first());
++                }
++            }
++            e.stop();
++            break;
++
++        case 65: // A
++        case 97: // a
++            if (e.ctrlKey) {
++                this.selectAll();
++                e.stop();
++            }
++            break;
++        }
++    },
++
++    /* Handle rename folder actions. */
++    renameFolder: function(folder)
++    {
++        if (Object.isUndefined(folder)) {
++            return;
++        }
++
++        folder = $(folder);
++        var n = this._createFolderForm(function(e) { this._folderAction(folder, e, 'rename'); return false; }.bindAsEventListener(this), DIMP.text.rename_prompt);
++        n.down('input').setValue(folder.readAttribute('l'));
++    },
++
++    /* Handle insert folder actions. */
++    createBaseFolder: function()
++    {
++        this._createFolderForm(function(e) { this._folderAction('', e, 'create'); return false; }.bindAsEventListener(this), DIMP.text.create_prompt);
++    },
++
++    createSubFolder: function(folder)
++    {
++        if (Object.isUndefined(folder)) {
++            return false;
++        }
++
++        this._createFolderForm(function(e) { this._folderAction($(folder), e, 'createsub'); return false; }.bindAsEventListener(this), DIMP.text.createsub_prompt);
++    },
++
++    _createFolderForm: function(action, text)
++    {
++        var n = new Element('FORM', { action: '#', id: 'RB_folder' }).insert(
++                    new Element('P').insert(text)
++                ).insert(
++                    new Element('INPUT', { type: 'text', size: 15 })
++                ).insert(
++                    new Element('INPUT', { type: 'button', className: 'button', value: DIMP.text.ok }).observe('click', action)
++                ).insert(
++                    new Element('INPUT', { type: 'button', className: 'button', value: DIMP.text.cancel }).observe('click', this.bcache.get('closeRB') || this.bcache.set('closeRB', this._closeRedBox.bind(this)))
++                ).observe('keydown', function(e) { if ((e.keyCode || e.charCode) == Event.KEY_RETURN) { e.stop(); action(e); } });
++
++        RedBox.overlay = true;
++        RedBox.onDisplay = Form.focusFirstElement.curry(n);
++        RedBox.showHtml(n);
++        return n;
++    },
++
++    _closeRedBox: function()
++    {
++        var c = RedBox.getWindowContents();
++        DimpCore.addGC([ c, c.descendants() ].flatten());
++        RedBox.close();
++    },
++
++    _folderAction: function(folder, e, mode)
++    {
++        this._closeRedBox();
++
++        var action, params, val,
++            form = e.findElement('form');
++        val = $F(form.down('input'));
++
++        if (val) {
++            switch (mode) {
++            case 'rename':
++                if (folder.readAttribute('l') != val) {
++                    action = 'RenameFolder';
++                    params = { old_name: folder.readAttribute('mbox'),
++                               new_parent: folder.up().hasClassName('folderlist') ? '' : folder.up(1).previous().readAttribute('mbox'),
++                               new_name: val };
++                }
++                break;
++
++            case 'create':
++            case 'createsub':
++                action = 'CreateFolder';
++                params = { folder: val };
++                if (mode == 'createsub') {
++                    params.parent = folder.readAttribute('mbox');
++                }
++                break;
++            }
++            if (action) {
++                DimpCore.doAction(action, params, [], this.bcache.get('folderC') || this.bcache.set('folderC', this._folderCallback.bind(this)));
++            }
++        }
++    },
++
++    /* Folder action callback functions. */
++    _folderCallback: function(r)
++    {
++        r = r.response;
++        r.d.each(this.deleteFolder.bind(this));
++        r.c.each(this.changeFolder.bind(this));
++        r.a.each(this.createFolder.bind(this));
++    },
++
++    _deleteCallback: function(r)
++    {
++        this.msgListLoading(false);
++        this._pollFoldersCallback(r);
++
++        if (!r.response.uids ||
++            r.response.folder != this.folder) {
++            return;
++        }
++
++        var search = this.viewport.getViewportSelection().search({ view: { equal: [ r.response.folder ] }, imapuid: { equal: r.response.uids[r.response.folder] } });
++        if (search.size()) {
++            if (r.response.remove) {
++                this.viewport.remove(search, { cacheid: r.response.cacheid, noupdate: r.response.viewport });
++                this._expirePPCache(search.get('uid'));
++            } else {
++                // Need this to catch spam deletions.
++                this.viewport.updateFlag(search, 'deletedmsg', true);
++            }
++        }
++    },
++
++    _emptyFolderCallback: function(r)
++    {
++        if (r.response.mbox) {
++            if (this.folder == r.response.mbox) {
++                this.viewport.reload();
++                this.clearPreviewPane();
++            }
++            this.setFolderLabel(r.response.mbox, 0);
++        }
++    },
++
++    _flagAllCallback: function(r)
++    {
++        if (r.response.mbox) {
++            this.setFolderLabel(r.response.mbox, r.response.u);
++        }
++    },
++
++    _folderLoadCallback: function(r)
++    {
++        this._folderCallback(r);
++
++        var elts = $('specialfolders', 'normalfolders').compact(),
++            nf = $('normalfolders'),
++            nfheight = nf.getStyle('max-height');
++
++        elts.invoke('observe', 'click', this._handleFolderMouseEvent.bindAsEventListener(this, 'click'));
++        elts.invoke('observe', 'mouseover', this._handleFolderMouseEvent.bindAsEventListener(this, 'over'));
++        if (DIMP.conf.is_ie6) {
++            elts.invoke('observe', 'mouseout', this._handleFolderMouseEvent.bindAsEventListener(this, 'out'));
++        }
++
++        $('foldersLoading').hide();
++        $('foldersSidebar').show();
++
++        // Fix for IE6 - which doesn't support max-height.  We need to search
++        // for height: 0px instead (comment in IE 6 CSS explains this is
++        // needed for auto sizing).
++        if (nfheight !== null ||
++            (Prototype.Browser.IE &&
++             Object.isUndefined(nfheight) &&
++             (nf.getStyle('height') == '0px'))) {
++            this._sizeFolderlist();
++            Event.observe(window, 'resize', this._sizeFolderlist.bind(this));
++        }
++
++        if (r.response.quota) {
++            $('quota').update(r.response.quota);
++        }
++    },
++
++    _handleFolderMouseEvent: function(e, action)
++    {
++        var type,
++            elt = e.element(),
++            li = elt.up('.folder') || elt.up('.custom');
++        if (!li) {
++            return;
++        }
++        type = li.readAttribute('ftype');
++
++        switch (action) {
++        case 'over':
++            if (DIMP.conf.is_ie6) {
++                li.addClassName('over');
++            }
++            if (type && !this.mo_sidebar.get(li.id)) {
++                DimpCore.addMouseEvents({ id: li.id, type: type });
++                this.mo_sidebar.set(li.id, 1);
++            }
++            break;
++
++        case 'out':
++            li.removeClassName('over');
++            break;
++
++        case 'click':
++            if (elt.hasClassName('exp') || elt.hasClassName('col')) {
++                this._toggleSubFolder(li.id, 'tog');
++            } else {
++                switch (type) {
++                case 'container':
++                    e.stop();
++                    break;
++
++                case 'folder':
++                case 'special':
++                    e.stop();
++                    return this.go('folder:' + li.readAttribute('mbox'));
++                    break;
++                }
++            }
++            break;
++        }
++    },
++
++    _toggleSubFolder: function(base, mode)
++    {
++        base = $(base);
++        var s = $(this.getSubFolderId(base.id));
++        if (s &&
++            (mode == 'tog' ||
++             (mode == 'exp' && !s.visible()) ||
++             (mode == 'col' && s.visible()))) {
++            base.firstDescendant().writeAttribute({ className: s.toggle().visible() ? 'col' : 'exp' });
++        }
++        if (base.descendantOf('specialfolders')) {
++            this._sizeFolderlist();
++        }
++    },
++
++    // Folder actions.
++    // For format of the ob object, see DIMP::_createFolderElt().
++    createFolder: function(ob)
++    {
++        var div, f_node, li, ll, parent_e,
++            fid = this.getFolderId(ob.m),
++            mbox = decodeURIComponent(ob.m),
++            submboxid = this.getSubFolderId(fid),
++            submbox = $(submboxid);
++
++        li = new Element('LI', { className: 'folder', id: fid, l: ob.l, mbox: mbox, ftype: ((ob.co) ? 'container' : ((ob.s) ? 'special' : 'folder')) });
++
++        div = new Element('DIV', { className: ob.cl || 'base', id: fid + '_div' });
++        if (ob.i) {
++            div.setStyle({ backgroundImage: 'url("' + ob.i + '")' });
++        }
++        if (ob.ch) {
++            div.writeAttribute({ className: 'exp' }).observe('mouseover', this.bcache.get('mo_folder') || this.bcache.set('mo_folder', function(e) {
++                e = e.element();
++                if (DragDrop.Drags.drag && e.hasClassName('exp')) {
++                    this._toggleSubFolder(e.up(), 'exp');
++                }
++            }.bindAsEventListener(this)));
++        }
++
++        li.insert(div).insert(new Element('A', { id: fid + '_label', title: ob.l }).insert(ob.l));
++
++        // Now walk through the parent <ul> to find the right place to
++        // insert the new folder.
++        if (submbox) {
++            if (submbox.insert({ before: li }).visible()) {
++                // If an expanded parent mailbox was deleted, we need to toggle
++                // the icon accordingly.
++                div.removeClassName('exp').addClassName('col');
++            }
++        } else {
++            if (ob.s) {
++                parent_e = $('specialfolders');
++            } else {
++                parent_e = $(this.getSubFolderId(this.getFolderId(ob.pa)));
++                parent_e = (parent_e) ? parent_e.down('UL') : $('normalfolders');
++            }
++
++            ll = mbox.toLowerCase();
++            f_node = parent_e.childElements().find(function(node) {
++                var nodembox = node.readAttribute('mbox');
++                return nodembox &&
++                       (!ob.s || nodembox != 'INBOX') &&
++                       (ll < nodembox.toLowerCase());
++            });
++
++            if (f_node) {
++                f_node.insert({ before: li });
++            } else {
++                parent_e.insert(li);
++            }
++
++            // Make sure the sub<mbox> ul is created if necessary.
++            if (ob.ch) {
++                li.insert({ after: new Element('LI', { className: 'subfolders', id: submboxid }).insert(new Element('UL')).hide() });
++            }
++        }
++
++        // Make the new folder a drop target.
++        new Drop(li, this._folderDropConfig);
++
++        // Check for unseen messages
++        if (ob.po) {
++            li.writeAttribute('u', '');
++            this.setFolderLabel(mbox, ob.u);
++        }
++    },
++
++    deleteFolder: function(folder)
++    {
++        var f = decodeURIComponent(folder), fid;
++        if (this.folder == f) {
++            this.go('folder:INBOX');
++        }
++
++        fid = this.getFolderId(folder);
++        this.deleteFolderElt(fid, true);
++    },
++
++    changeFolder: function(ob)
++    {
++        var fid = this.getFolderId(ob.m),
++            fdiv = $(fid + '_div'),
++            oldexpand = fdiv && fdiv.hasClassName('col');
++        this.deleteFolderElt(fid, !ob.ch);
++        if (ob.co && this.folder == ob.m) {
++            this.go('folder:INBOX');
++        }
++        this.createFolder(ob);
++        if (ob.ch && oldexpand) {
++            fdiv.removeClassName('exp').addClassName('col');
++        }
++    },
++
++    deleteFolderElt: function(fid, sub)
++    {
++        var f = $(fid);
++        DimpCore.addGC($(f, fid + '_div', fid + '_label'));
++        if (sub) {
++            var submbox = $(this.getSubFolderId(fid));
++            if (submbox) {
++                submbox.remove();
++            }
++        }
++        [ DragDrop.Drags.get_drag(fid), DragDrop.Drops.get_drop(fid) ].compact().invoke('destroy');
++        DimpCore.removeMouseEvents(f);
++        this.mo_sidebar.unset(fid, 1);
++        DimpCore.addGC(f);
++        if (this.viewport) {
++            this.viewport.deleteView(fid);
++        }
++        f.remove();
++    },
++
++    _sizeFolderlist: function()
++    {
++        var nf = $('normalfolders');
++        nf.setStyle({ height: (document.viewport.getHeight() - nf.cumulativeOffset()[1] - 10) + 'px' });
++    },
++
++    /* Flag actions for message list. */
++    flag: function(action, index, folder)
++    {
++        var actionCall, args, vs,
++            obs = [],
++            unseenstatus = 1;
++
++        if (index) {
++            if (Object.isUndefined(folder)) {
++                vs = this.viewport.createSelection('dataob', index);
++            } else {
++                vs = this.viewport.getViewportSelection().search({ imapuid: { equal: [ index ] }, view: { equal: [ folder ] } });
++                if (!vs.size() && folder != this.folder) {
++                    vs = this.viewport.getViewportSelection(folder).search({ imapuid: { equal: [ index ] } });
++                }
++            }
++        } else {
++            vs = this.viewport.getSelected();
++        }
++
++        switch (action) {
++        case 'allUnseen':
++        case 'allSeen':
++            DimpCore.doAction((action == 'allUnseen') ? 'MarkFolderUnseen' : 'MarkFolderSeen', { folder: folder }, [], this.bcache.get('flagAC') || this.bcache.set('flagAC', this._flagAllCallback.bind(this)));
++            if (folder == this.folder) {
++                this.viewport.updateFlag(this.createSelection('rownum', $A($R(1, this.viewport.getMetaData('total_rows')))), 'unseen', action == 'allUnseen');
++            }
++            break;
++
++        case 'deleted':
++        case 'undeleted':
++        case 'spam':
++        case 'ham':
++        case 'blacklist':
++        case 'whitelist':
++            if (!vs.size()) {
++                break;
++            }
++
++            // 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).
++            if (action == 'deleted') {
++                vs = vs.search({ isdel: { not: [ true ] } });
++                if (!vs.size()) {
++                    break;
++                }
++                vs.set({ isdel: true });
++            } else if (action == 'undeleted') {
++                vs.set({ isdel: false });
++            }
++
++            args = this.viewport.addRequestParams({});
++            if (action == 'deleted' || action == 'undeleted') {
++                this.viewport.updateFlag(vs, 'deletedmsg', action == 'deleted');            }
++
++            if (action == 'undeleted') {
++                DimpCore.doAction('UndeleteMessage', args, DimpCore.toUIDArray(vs));
++            } else {
++                actionCall = { deleted: 'DeleteMessage', spam: 'ReportSpam', ham: 'ReportHam', blacklist: 'Blacklist', whitelist: 'Whitelist' };
++                // This needs to be synchronous Ajax if we are calling from a
++                // popup window because Mozilla will not correctly call the
++                // callback function if the calling window has been closed.
++                DimpCore.doAction(actionCall[action], args, DimpCore.toUIDArray(vs), this.bcache.get('deleteC') || this.bcache.set('deleteC', this._deleteCallback.bind(this)), { asynchronous: !(index && folder) });
++
++                // If reporting spam, to indicate to the user that something is
++                // happening (since spam reporting may not be instantaneous).
++                if (action == 'spam' || action == 'ham') {
++                    this.msgListLoading(true);
++                }
++            }
++            break;
++
++        case 'unseen':
++        case 'seen':
++            if (!vs.size()) {
++                break;
++            }
++            args = { folder: this.folder, messageFlag: '-seen' };
++            if (action == 'seen') {
++                unseenstatus = 0;
++                args.messageFlag = 'seen';
++            }
++            vs.get('dataob').each(function(s) {
++                if (this.updateUnseenUID(s, unseenstatus)) {
++                    obs.push(s);
++                }
++            }, this);
++
++            if (obs.size()) {
++                DimpCore.doAction('MarkMessage', args, DimpCore.toUIDArray(this.viewport.createSelection('dataob', obs)));
++            }
++            break;
++
++        case 'flagged':
++        case 'clear':
++            if (!vs.size()) {
++                break;
++            }
++            args = {
++                folder: this.folder,
++                messageFlag: ((action == 'flagged') ? 'flagged' : '-flagged')
++            };
++            this.viewport.updateFlag(vs, 'flagged', action == 'flagged');
++            DimpCore.doAction('MarkMessage', args, DimpCore.toUIDArray(vs));
++            break;
++
++        case 'answered':
++            this.viewport.updateFlag(vs, 'answered', true);
++            this.viewport.updateFlag(vs, 'flagged', false);
++            break;
++        }
++    },
++
++    /* Miscellaneous folder actions. */
++    purgeDeleted: function()
++    {
++        DimpCore.doAction('PurgeDeleted', this.viewport.addRequestParams({}), [], this.bcache.get('deleteC') || this.bcache.set('deleteC', this._deleteCallback.bind(this)));
++    },
++
++    modifyPollFolder: function(folder, add)
++    {
++        DimpCore.doAction('ModifyPollFolder', { folder: folder, add: (add) ? 1 : 0 }, [], this.bcache.get('modifyPFC') || this.bcache.set('modifyPFC', this._modifyPollFolderCallback.bind(this)));
++    },
++
++    _modifyPollFolderCallback: function(r)
++    {
++        r = r.response;
++        var f = r.folder, fid, p = { response: { poll: {} } };
++        fid = $(this.getFolderId(f));
++
++        if (r.add) {
++            p.response.poll[f] = r.poll.u;
++            fid.writeAttribute('u', 0);
++        } else {
++            p.response.poll[f] = 0;
++        }
++
++        this._pollFoldersCallback(p);
++
++        if (!r.add) {
++            fid.removeAttribute('u');
++        }
++    },
++
++    msgListLoading: function(show)
++    {
++        var ml_offset;
++
++        if (this.fl_visible != show) {
++            this.fl_visible = show;
++            if (show) {
++                ml_offset = $('msgList').positionedOffset();
++                $('folderLoading').setStyle({ position: 'absolute', top: (ml_offset.top + 10) + 'px', left: (ml_offset.left + 10) + 'px' });
++                Effect.Appear('folderLoading', { duration: 0.2 });
++                $(document.body).setStyle({ cursor: 'progress' });
++            } else {
++                Effect.Fade('folderLoading', { duration: 0.2 });
++                $(document.body).setStyle({ cursor: 'default' });
++            }
++        }
++    },
++
++    // p = (element) Parent element
++    // c = (element) Child element
++    isSubfolder: function(p, c)
++    {
++        var sf = $(this.getSubFolderId(p.readAttribute('id')));
++        return sf && c.descendantOf(sf);
++    },
++
++    /* Onload function. */
++    _onLoad: function() {
++        var C = DimpCore.clickObserveHandler, tmp;
++
++        if (Horde.dhtmlHistory.initialize()) {
++            Horde.dhtmlHistory.addListener(this.go.bind(this));
++        }
++
++        this._setFilterText(true);
++
++        /* Initialize the starting page if necessary. addListener() will have
++         * already fired if there is a current location so only do a go()
++         * call if there is no current location. */
++        if (!Horde.dhtmlHistory.getCurrentLocation()) {
++            if (DIMP.conf.login_view == 'inbox') {
++                this.go('folder:INBOX');
++            } else {
++                this.go('portal');
++                if (DIMP.conf.background_inbox) {
++                    this.loadFolder('INBOX', true);
++                }
++            }
++        }
++
++        /* Add popdown menus. */
++        DimpCore.addPopdown('button_reply', 'reply');
++        DimpCore.DMenu.disable('button_reply_img', true, true);
++        DimpCore.addPopdown('button_forward', 'forward');
++        DimpCore.DMenu.disable('button_forward_img', true, true);
++        DimpCore.addPopdown('button_other', 'otheractions');
++
++        /* Set up click event observers for elements on main page. */
++        tmp = $('logo');
++        if (tmp.visible()) {
++            C({ d: tmp.down('a'), f: this.go.bind(this, 'portal') });
++        }
++
++        tmp = $('dimpbarActions');
++        C({ d: tmp.down('.composelink'), f: DimpCore.compose.bind(DimpCore, 'new') });
++        C({ d: tmp.down('.refreshlink'), f: this.pollFolders.bind(this) });
++
++        tmp = $('serviceActions');
++        [ 'portal', 'options' ].each(function(a) {
++            var d = $('app' + a);
++            if (d) {
++                C({ d: d, f: this.go.bind(this, a) });
++            }
++        }, this);
++        tmp = $('applogout');
++        if (tmp) {
++            C({ d: tmp, f: DimpCore.logout.bind(DimpCore) });
++        }
++
++        tmp = $('applicationfolders');
++        if (tmp) {
++            tmp.select('ul li.custom a').each(function(s) {
++                C({ d: s, f: this.go.bind(this, 'app:' + s.readAttribute('app')) });
++            }, this);
++        }
++
++        C({ d: $('newfolder'), f: this.createBaseFolder.bind(this) });
++        new Drop('dropbase', this._folderDropConfig);
++        tmp = $('hometab');
++        if (tmp) {
++            C({ d: tmp, f: this.go.bind(this, 'portal') });
++        }
++        $('tabbar').select('a.applicationtab').each(function(a) {
++            C({ d: a, f: this.go.bind(this, 'app:' + a.readAttribute('app')) });
++        }, this);
++        C({ d: $('button_reply'), f: this.composeMailbox.bind(this, 'reply'), ns: true });
++        C({ d: $('button_forward'), f: this.composeMailbox.bind(this, DIMP.conf.forward_default), ns: true });
++        [ 'spam', 'ham', 'deleted' ].each(function(a) {
++            var d = $('button_' + a);
++            if (d) {
++                C({ d: d, f: this.flag.bind(this, a) });
++            }
++        }, this);
++        C({ d: $('button_compose'), f: DimpCore.compose.bind(DimpCore, 'new') });
++        C({ d: $('button_other'), f: function(e) { DimpCore.DMenu.trigger(e.findElement('A').next(), true); }, p: true });
++        C({ d: $('qoptions').down('.qclose a'), f: this.searchfilterClear.bind(this, false) });
++        [ 'all', 'current' ].each(function(a) {
++            var d = $('sf_' + a);
++            if (d) {
++                C({ d: d, f: this.updateSearchfilter.bind(this, a, 'folder') });
++            }
++        }, this);
++        [ 'msgall', 'from', 'to', 'subject' ].each(function(a) {
++            C({ d: $('sf_' + a), f: this.updateSearchfilter.bind(this, a, 'msg') });
++        }, this);
++        C({ d: $('msglistHeader'), f: this.sort.bind(this), p: true });
++        C({ d: $('ctx_folder_create'), f: function() { this.createSubFolder(DimpCore.DMenu.element()); }.bind(this), ns: true });
++        C({ d: $('ctx_folder_rename'), f: function() { this.renameFolder(DimpCore.DMenu.element()); }.bind(this), ns: true });
++        C({ d: $('ctx_folder_empty'), f: function() { if (window.confirm(DIMP.text.empty_folder)) { DimpCore.doAction('EmptyFolder', { folder: DimpCore.DMenu.element().readAttribute('mbox') }, [], this._emptyFolderCallback.bind(this)); } }.bind(this), ns: true });
++        C({ d: $('ctx_folder_delete'), f: function() { if (window.confirm(DIMP.text.delete_folder)) { DimpCore.doAction('DeleteFolder', { folder: DimpCore.DMenu.element().readAttribute('mbox') }, [], this.bcache.get('folderC') || this.bcache.set('folderC', this._folderCallback.bind(this))); } }.bind(this), ns: true });
++        [ 'ctx_folder_seen', 'ctx_folder_unseen' ].each(function(a) {
++            C({ d: $(a), f: function(type) { this.flag(type, null, DimpCore.DMenu.element().readAttribute('mbox')); }.bind(this, a == 'ctx_folder_seen' ? 'allSeen' : 'allUnseen'), ns: true });
++        }, this);
++        [ 'ctx_folder_poll', 'ctx_folder_nopoll' ].each(function(a) {
++            C({ d: $(a), f: function(modify) { this.modifyPollFolder(DimpCore.DMenu.element().readAttribute('mbox'), modify); }.bind(this, a == 'ctx_folder_poll'), ns: true });
++        }, this);
++        C({ d: $('ctx_container_create'), f: function() { this.createSubFolder(DimpCore.DMenu.element()); }.bind(this), ns: true });
++        C({ d: $('ctx_container_rename'), f: function() { this.renameFolder(DimpCore.DMenu.element()); }.bind(this), ns: true });
++        [ 'reply', 'reply_all', 'reply_list', 'forward_all', 'forward_body', 'forward_attachments' ].each(function(a) {
++            C({ d: $('ctx_message_' + a), f: this.composeMailbox.bind(this, a), ns: true });
++        }, this);
++        [ 'seen', 'unseen', 'flagged', 'clear', 'spam', 'ham', 'blacklist', 'whitelist', 'deleted', 'undeleted' ].each(function(a) {
++            var d = $('ctx_message_' + a);
++            if (d) {
++                C({ d: d, f: this.flag.bind(this, a), ns: true });
++            }
++        }, this);
++        C({ d: $('ctx_draft_resume'), f: this.composeMailbox.bind(this, 'resume') });
++        [ 'flagged', 'clear', 'deleted', 'undeleted' ].each(function(a) {
++            var d = $('ctx_draft_' + a);
++            if (d) {
++                C({ d: d, f: this.flag.bind(this, a), ns: true });
++            }
++        }, this);
++        [ 'reply', 'reply_all', 'reply_list' ].each(function(a) {
++            C({ d: $('ctx_reply_' + a), f: this.composeMailbox.bind(this, a), ns: true });
++        }, this);
++        [ 'forward_all', 'forward_body', 'forward_attachments' ].each(function(a) {
++            C({ d: $('ctx_forward_' + a), f: this.composeMailbox.bind(this, a), ns: true });
++        }, this);
++        C({ d: $('previewtoggle'), f: this.togglePreviewPane.bind(this), ns: true });
++        [ 'seen', 'unseen', 'flagged', 'clear', 'blacklist', 'whitelist', 'undeleted' ].each(function(a) {
++            var d = $('oa_' + a);
++            if (d) {
++                C({ d: d, f: this.flag.bind(this, a), ns: true });
++            }
++        }, this);
++        C({ d: $('oa_selectall'), f: this.selectAll.bind(this), ns: true });
++
++        tmp = $('oa_purge_deleted');
++        if (tmp) {
++            C({ d: tmp, f: this.purgeDeleted.bind(this), ns: true });
++        }
++
++        $('expandHeaders', 'collapseHeaders').each(function(a) {
++            C({ d: a, f: function() { $('msgHeadersColl', 'msgHeaders').invoke('toggle'); }, ns: true });
++        }, this);
++        $('msg_newwin', 'msg_newwin_options').compact().each(function(a) {
++            C({ d: a, f: function() { this.msgWindow(this.viewport.getViewportSelection().search({ imapuid: { equal: [ DIMP.conf.msg_index ] } , view: { equal: [ DIMP.conf.msg_folder ] } }).get('dataob').first()); }.bind(this) });
++        }, this);
++        DimpCore.messageOnLoad();
++        this._resizeIE6();
++    },
++
++    // IE 6 width fixes (See Bug #6793)
++    _resizeIE6: function()
++    {
++        if (DIMP.conf.is_ie6) {
++            var tmp = parseInt($('sidebarPanel').getStyle('width'), 10),
++                tmp1 = document.viewport.getWidth() - tmp - 30;
++            $('normalfolders').setStyle({ width: tmp + 'px' });
++            $('dimpmain').setStyle({ width: tmp1 + 'px' });
++            $('msglist').setStyle({ width: (tmp1 - 5) + 'px' });
++            $('msgBody').setStyle({ width: (tmp1 - 25) + 'px' });
++            tmp = $('dimpmain_portal').down('IFRAME');
++            if (tmp) {
++                this._resizeIE6Iframe(tmp);
++            }
++        }
++    },
++
++    _resizeIE6Iframe: function(iframe)
++    {
++        if (DIMP.conf.is_ie6) {
++            iframe.setStyle({ width: $('dimpmain').getStyle('width'), height: (document.viewport.getHeight() - 20) + 'px' });
++        }
++    }
++};
++
++/* Need to add after DimpBase is defined. */
++DimpBase._msgDragConfig = {
++    scroll: 'normalfolders',
++    threshold: 5,
++    caption: DimpBase._dragCaption.bind(DimpBase),
++    onStart: function(d, e) {
++        var args = { right: e.isRightClick() },
++            id = d.element.id;
++
++        d.selectIfNoDrag = false;
++
++        // Handle selection first.
++        if (!args.right && (e.ctrlKey || e.metaKey)) {
++            this.msgSelect(id, $H({ ctrl: true }).merge(args).toObject());
++        } else if (e.shiftKey) {
++            this.msgSelect(id, $H({ shift: true }).merge(args).toObject());
++        } else if (this.isSelected('domid', id)) {
++            if (!args.right && this.selectedCount()) {
++                d.selectIfNoDrag = true;
++            }
++        } else {
++            this.msgSelect(id, args);
++        }
++    }.bind(DimpBase),
++    onEnd: function(d, e) {
++        if (d.selectIfNoDrag && !d.wasDragged) {
++            this.msgSelect(d.element.id, { right: e.isRightClick() });
++        }
++    }.bind(DimpBase)
++};
++
++DimpBase._folderDragConfig = {
++    ghosting: true,
++    offset: { x: 5, y: 5 },
++    scroll: 'normalfolders',
++    threshold: 5,
++    onDrag: function(d, e) {
++        if (!d.wasDragged) {
++            $('newfolder').hide();
++            $('dropbase').show();
++            d.ghost.removeClassName('on');
++        }
++    },
++    onEnd: function(d, e) {
++        if (d.wasDragged) {
++            $('newfolder').show();
++            $('dropbase').hide();
++        }
++    }
++};
++
++DimpBase._folderDropConfig = {
++    hoverclass: 'dragdrop',
++    caption: function(drop, drag) {
++        var d = drag.readAttribute('l'),
++            ftype = drop.readAttribute('ftype'),
++            l = drop.readAttribute('l'),
++            m = DIMP.text.moveto;
++        if (drop == $('dropbase')) {
++            return m.replace(/%s/, d).replace(/%s/, DIMP.text.baselevel);
++        } else if (drag.hasClassName('folder')) {
++            return (ftype != 'special' && !this.isSubfolder(drag, drop)) ? m.replace(/%s/, d).replace(/%s/, l) : '';
++        } else {
++            return ftype != 'container' ? m.replace(/%s/, this._dragCaption()).replace(/%s/, l) : '';
++        }
++    }.bind(DimpBase),
++    onDrop: DimpBase._folderDropHandler.bind(DimpBase)
++};
++
++/* Stuff to do immediately when page is ready. */
++document.observe('dom:loaded', function() {
++    $('dimpLoading').hide();
++    $('dimpPage').show();
++
++    /* Create the folder list. Any pending notifications will be caught via
++     * the return from this call. */
++    DimpCore.doAction('ListFolders', {}, [], DimpBase._folderLoadCallback.bind(DimpBase));
++
++    /* Start message list loading as soon as possible. */
++    if (!DimpBase.delay_onload) {
++        DimpBase._onLoad();
++    }
++
++    /* Disable text selection in preview pane for IE 6. */
++    if (DIMP.conf.is_ie6) {
++        document.observe('selectstart', Event.stop);
++    }
++
++    /* Remove unneeded search folders. */
++    if (!DIMP.conf.search_all) {
++        DimpBase.sfiltersfolder.unset('sf_all');
++    }
++
++    /* Check for new mail. */
++    DimpBase.setPollFolders();
++
++    /* Bind key shortcuts. */
++    document.observe('keydown', DimpBase._keydownHandler.bind(DimpBase));
++
++    /* Resize elements on window size change. */
++    Event.observe(window, 'resize', DimpBase._onResize.bind(DimpBase));
++
++    /* Since IE 6 doesn't support hover over non-links, use javascript events
++     * to replicate mouseover CSS behavior. */
++    if (DIMP.conf.is_ie6) {
++        var links = [], tmp;
++        if (tmp = $('dimpbarActions')) {
++            links.push(tmp.select('SPAN'));
++        }
++        if (tmp = $('serviceActions')) {
++            links.push(tmp.select('LI.servicelink'));
++        }
++        if (tmp = $('applicationfolders')) {
++            links.push(tmp.select('UL LI'));
++        }
++        links.flatten().compact().each(function(e) {
++            e.observe('mouseover', e.addClassName.curry('over')).observe('mouseout', e.removeClassName.curry('over'));
++        });
++    }
++});
++
++/* Stuff to do after window is completely loaded. Don't init viewport until
++ * now for non-Gecko/Opera browsers since sizing functions might not work
++ * properly before. */
++if (DimpBase.delay_onload) {
++    Event.observe(window, 'load', DimpBase._onLoad.bind(DimpBase));
++}
++
++/* Need to register a callback function for doAction to catch viewport
++ * information returned from the server. */
++DimpCore.onDoActionComplete = function(r) {
++    if (DimpBase.viewport && r.response.viewport) {
++        DimpBase.viewport.ajaxResponse(r.response.viewport);
++    }
++};
++
++/* Extend these functions from DimpCore since additional processing needs to
++ * be done re: drag/drop and menu manipulation. */
++DimpCore.addMouseEvents = DimpCore.addMouseEvents.wrap(DimpBase._addMouseEvents.bind(DimpBase));
++DimpCore.removeMouseEvents = DimpCore.removeMouseEvents.wrap(DimpBase._removeMouseEvents.bind(DimpBase));
+diff -ur dimp-h3-1.1.6.orig/js/src/DimpBase.js dimp-h3-1.1.6/js/src/DimpBase.js
+--- dimp-h3-1.1.6.orig/js/src/DimpBase.js	2010-09-27 19:14:34.000000000 +0100
++++ dimp-h3-1.1.6/js/src/DimpBase.js	2011-01-10 23:49:33.897945000 +0000
+@@ -1548,7 +1548,7 @@
+ 
+         div = new Element('DIV', { className: ob.cl || 'base', id: fid + '_div' });
+         if (ob.i) {
+-            div.update(ob.i);
++            div.setStyle({ backgroundImage: 'url("' + ob.i + '")' });
+         }
+         if (ob.ch) {
+             div.writeAttribute({ className: 'exp' }).observe('mouseover', this.bcache.get('mo_folder') || this.bcache.set('mo_folder', function(e) {
+Only in dimp-h3-1.1.6/js/src: DimpBase.js.orig
+diff -ur dimp-h3-1.1.6.orig/lib/DIMP.php dimp-h3-1.1.6/lib/DIMP.php
+--- dimp-h3-1.1.6.orig/lib/DIMP.php	2010-09-27 19:14:30.000000000 +0100
++++ dimp-h3-1.1.6/lib/DIMP.php	2011-01-10 23:49:33.897945000 +0000
+@@ -436,8 +436,13 @@
+         }
+ 
+         if ($elt['user_icon']) {
+-            $ob->cl = 'custom';
+-            $ob->i = Horde::img($elt['icon'], $elt['alt'], '', $elt['icondir']);
++            $ob->cl = 'customimg';
++            $dir = empty($elt['icondir'])
++                ? $GLOBALS['registry']->getImageDir()
++                : $elt['icondir'];
++            $ob->i = empty($dir)
++                ? $elt['icon']
++                : $dir . '/' . $elt['icon'];
+         }
+ 
+         return $ob;
+Only in dimp-h3-1.1.6/lib: DIMP.php.orig
+diff -ur dimp-h3-1.1.6.orig/themes/screen.css dimp-h3-1.1.6/themes/screen.css
+--- dimp-h3-1.1.6.orig/themes/screen.css	2008-09-05 15:17:01.000000000 +0100
++++ dimp-h3-1.1.6/themes/screen.css	2011-01-10 23:49:33.897945000 +0000
+@@ -464,7 +464,7 @@
+     height: 100%;
+     background: transparent url("graphics/folder_create.png") center left no-repeat;
+ }
+-#sidebarPanel .drafts, #sidebarPanel .inbox, #sidebarPanel .sent, #sidebarPanel .spam, #sidebarPanel .trash {
++#sidebarPanel .drafts, #sidebarPanel .inbox, #sidebarPanel .sent, #sidebarPanel .spam, #sidebarPanel .trash, #sidebarPanel .customimg {
+     display: inline;
+     float: left;
+     width: 20px;
diff --git a/kolab-webclient/dimp/patches/dimp-1.1.6/0002-close-context-menu.patch b/kolab-webclient/dimp/patches/dimp-1.1.6/0002-close-context-menu.patch
new file mode 100644
index 0000000..ab764f0
--- /dev/null
+++ b/kolab-webclient/dimp/patches/dimp-1.1.6/0002-close-context-menu.patch
@@ -0,0 +1,21 @@
+diff -ur dimp-h3-1.1.6-0001-fix-broken-folder-images/js/DimpBase.js dimp-h3-1.1.6/js/DimpBase.js
+--- dimp-h3-1.1.6-0001-fix-broken-folder-images/js/DimpBase.js	2011-01-10 23:49:33.895945000 +0000
++++ dimp-h3-1.1.6/js/DimpBase.js	2011-01-10 23:50:59.238945002 +0000
+@@ -1510,6 +1510,7 @@
+ 
+                 case 'folder':
+                 case 'special':
++                    DimpCore.DMenu.close();
+                     e.stop();
+                     return this.go('folder:' + li.readAttribute('mbox'));
+                     break;
+@@ -1887,7 +1888,7 @@
+         tmp = $('applicationfolders');
+         if (tmp) {
+             tmp.select('ul li.custom a').each(function(s) {
+-                C({ d: s, f: this.go.bind(this, 'app:' + s.readAttribute('app')) });
++                C({ d: s, f: function(data){DimpCore.DMenu.close(); this.go('app:' + s.readAttribute('app'), data)}.bind(this) });
+             }, this);
+         }
+ 
+Only in dimp-h3-1.1.6/js: DimpBase.js.orig
diff --git a/kolab-webclient/dimp/patches/dimp-1.1.6/0003-acl-view.patch b/kolab-webclient/dimp/patches/dimp-1.1.6/0003-acl-view.patch
new file mode 100644
index 0000000..d537ee6
--- /dev/null
+++ b/kolab-webclient/dimp/patches/dimp-1.1.6/0003-acl-view.patch
@@ -0,0 +1,83 @@
+diff -ur dimp-h3-1.1.6-0002-close-context-menu/js/DimpBase.js dimp-h3-1.1.6/js/DimpBase.js
+--- dimp-h3-1.1.6-0002-close-context-menu/js/DimpBase.js	2011-01-10 23:50:59.238945002 +0000
++++ dimp-h3-1.1.6/js/DimpBase.js	2011-01-10 23:52:13.909945003 +0000
+@@ -1926,6 +1926,7 @@
+         C({ d: $('ctx_folder_rename'), f: function() { this.renameFolder(DimpCore.DMenu.element()); }.bind(this), ns: true });
+         C({ d: $('ctx_folder_empty'), f: function() { if (window.confirm(DIMP.text.empty_folder)) { DimpCore.doAction('EmptyFolder', { folder: DimpCore.DMenu.element().readAttribute('mbox') }, [], this._emptyFolderCallback.bind(this)); } }.bind(this), ns: true });
+         C({ d: $('ctx_folder_delete'), f: function() { if (window.confirm(DIMP.text.delete_folder)) { DimpCore.doAction('DeleteFolder', { folder: DimpCore.DMenu.element().readAttribute('mbox') }, [], this.bcache.get('folderC') || this.bcache.set('folderC', this._folderCallback.bind(this))); } }.bind(this), ns: true });
++        C({ d: $('ctx_folder_rights'), f: function() { this.go('app:horde', DIMP.conf.folder_rights + '&' + $H({ folder: DimpCore.DMenu.element().readAttribute('mbox') }).toQueryString() ) }.bind(this), ns: true });
+         [ 'ctx_folder_seen', 'ctx_folder_unseen' ].each(function(a) {
+             C({ d: $(a), f: function(type) { this.flag(type, null, DimpCore.DMenu.element().readAttribute('mbox')); }.bind(this, a == 'ctx_folder_seen' ? 'allSeen' : 'allUnseen'), ns: true });
+         }, this);
+diff -ur dimp-h3-1.1.6-0002-close-context-menu/js/DimpBase.js.orig dimp-h3-1.1.6/js/DimpBase.js.orig
+--- dimp-h3-1.1.6-0002-close-context-menu/js/DimpBase.js.orig	2011-01-10 23:49:33.895945000 +0000
++++ dimp-h3-1.1.6/js/DimpBase.js.orig	2011-01-10 23:50:59.238945002 +0000
+@@ -1510,6 +1510,7 @@
+ 
+                 case 'folder':
+                 case 'special':
++                    DimpCore.DMenu.close();
+                     e.stop();
+                     return this.go('folder:' + li.readAttribute('mbox'));
+                     break;
+@@ -1887,7 +1888,7 @@
+         tmp = $('applicationfolders');
+         if (tmp) {
+             tmp.select('ul li.custom a').each(function(s) {
+-                C({ d: s, f: this.go.bind(this, 'app:' + s.readAttribute('app')) });
++                C({ d: s, f: function(data){DimpCore.DMenu.close(); this.go('app:' + s.readAttribute('app'), data)}.bind(this) });
+             }, this);
+         }
+ 
+diff -ur dimp-h3-1.1.6-0002-close-context-menu/lib/DIMP.php dimp-h3-1.1.6/lib/DIMP.php
+--- dimp-h3-1.1.6-0002-close-context-menu/lib/DIMP.php	2011-01-10 23:49:33.897945000 +0000
++++ dimp-h3-1.1.6/lib/DIMP.php	2011-01-10 23:52:13.910945003 +0000
+@@ -166,6 +166,7 @@
+             'message_url' => Horde::url($dimp_webroot . '/message.php'),
+             'compose_url' => Horde::url($dimp_webroot . '/compose.php'),
+             'prefs_url' => str_replace('&', '&', Horde::getServiceLink('options', 'dimp')),
++	    'folder_rights' => Util::addParameter(Horde::url($registry->get('webroot', 'imp') . '/acl.php', true), array('app' => 'imp', 'group'=> 'acl'), null, false),
+ 
+             'sortthread' => SORTTHREAD,
+             'sortdate' => SORTDATE,
+diff -ur dimp-h3-1.1.6-0002-close-context-menu/lib/DIMP.php.orig dimp-h3-1.1.6/lib/DIMP.php.orig
+--- dimp-h3-1.1.6-0002-close-context-menu/lib/DIMP.php.orig	2010-09-27 19:14:30.000000000 +0100
++++ dimp-h3-1.1.6/lib/DIMP.php.orig	2011-01-10 23:49:33.897945000 +0000
+@@ -436,8 +436,13 @@
+         }
+ 
+         if ($elt['user_icon']) {
+-            $ob->cl = 'custom';
+-            $ob->i = Horde::img($elt['icon'], $elt['alt'], '', $elt['icondir']);
++            $ob->cl = 'customimg';
++            $dir = empty($elt['icondir'])
++                ? $GLOBALS['registry']->getImageDir()
++                : $elt['icondir'];
++            $ob->i = empty($dir)
++                ? $elt['icon']
++                : $dir . '/' . $elt['icon'];
+         }
+ 
+         return $ob;
+diff -ur dimp-h3-1.1.6-0002-close-context-menu/po/de_DE.po dimp-h3-1.1.6/po/de_DE.po
+--- dimp-h3-1.1.6-0002-close-context-menu/po/de_DE.po	2010-10-25 13:50:13.000000000 +0100
++++ dimp-h3-1.1.6/po/de_DE.po	2011-01-10 23:52:13.910945003 +0000
+@@ -798,3 +798,6 @@
+ #: lib/DIMP.php:216
+ msgid "results found"
+ msgstr "Ergebnisse gefunden"
++
++msgid "Share Folder"
++msgstr "Berechtigungen"
+Only in dimp-h3-1.1.6/po: de_DE.po.orig
+diff -ur dimp-h3-1.1.6-0002-close-context-menu/templates/index/index.inc dimp-h3-1.1.6/templates/index/index.inc
+--- dimp-h3-1.1.6-0002-close-context-menu/templates/index/index.inc	2008-12-07 22:22:20.000000000 +0000
++++ dimp-h3-1.1.6/templates/index/index.inc	2011-01-10 23:52:13.911945002 +0000
+@@ -323,6 +323,7 @@
+  <a id="ctx_folder_rename"><?php echo $folder_edit . _("Rename Folder") ?></a>
+  <a id="ctx_folder_empty"><?php echo $delete . _("Empty Folder") ?></a>
+  <a id="ctx_folder_delete"><?php echo Horde::img('folders/folder_delete.png') . _("Delete Folder") ?></a>
++ <a id="ctx_folder_rights"><?php echo Horde::img('folders/folder.png') . _("Share Folder") ?></a>
+  <div id="ctx_folder_seen_sep" class="sep"></div>
+  <a id="ctx_folder_seen"><?php echo $mailseen . _("Mark all as Read") ?></a>
+  <a id="ctx_folder_unseen"><?php echo $mailunseen . _("Mark all as New") ?></a>
diff --git a/kolab-webclient/dimp/patches/dimp-1.1.6/0004-folders-view.patch b/kolab-webclient/dimp/patches/dimp-1.1.6/0004-folders-view.patch
new file mode 100644
index 0000000..d448885
--- /dev/null
+++ b/kolab-webclient/dimp/patches/dimp-1.1.6/0004-folders-view.patch
@@ -0,0 +1,41 @@
+diff -ur dimp-h3-1.1.6-0003-acl-view/config/menu.php.dist dimp-h3-1.1.6/config/menu.php.dist
+--- dimp-h3-1.1.6-0003-acl-view/config/menu.php.dist	2008-03-10 20:19:35.000000000 +0000
++++ dimp-h3-1.1.6/config/menu.php.dist	2011-01-10 23:53:29.632945001 +0000
+@@ -28,3 +28,14 @@
+ //         'text' => 'Say Hi!',
+ //         'icon' => $GLOBALS['registry']->getImageDir('horde') . '/horde.png'),
+ // );
++
++// Load configuration files in .d directory
++$directory = dirname(__FILE__) . '/menu.d';
++if (file_exists($directory) && is_dir($directory)) {
++    $sub_files = glob("$directory/*.php");
++    if ($sub_files) {
++        foreach ($sub_files as $sub_file) {
++            require_once $sub_file;
++        }
++    }
++ }
+diff -ur dimp-h3-1.1.6-0003-acl-view/po/de_DE.po dimp-h3-1.1.6/po/de_DE.po
+--- dimp-h3-1.1.6-0003-acl-view/po/de_DE.po	2011-01-10 23:52:13.910945003 +0000
++++ dimp-h3-1.1.6/po/de_DE.po	2011-01-10 23:53:29.633945001 +0000
+@@ -17,6 +17,9 @@
+ "Content-Transfer-Encoding: 8bit\n"
+ "Plural-Forms: nplurals=2; plural=(n != 1);\n"
+ 
++msgid "Folder Subscription"
++msgstr "Ordner verwalten"
++
+ #: lib/Views/ShowMessage.php:295
+ #, php-format
+ msgid "%d Attachment"
+diff -ur dimp-h3-1.1.6-0003-acl-view/po/de_DE.po.orig dimp-h3-1.1.6/po/de_DE.po.orig
+--- dimp-h3-1.1.6-0003-acl-view/po/de_DE.po.orig	2010-10-25 13:50:13.000000000 +0100
++++ dimp-h3-1.1.6/po/de_DE.po.orig	2011-01-10 23:52:13.910945003 +0000
+@@ -798,3 +798,6 @@
+ #: lib/DIMP.php:216
+ msgid "results found"
+ msgstr "Ergebnisse gefunden"
++
++msgid "Share Folder"
++msgstr "Berechtigungen"
diff --git a/kolab-webclient/dimp/patches/dimp-1.1.6/0005-itip-handling.patch b/kolab-webclient/dimp/patches/dimp-1.1.6/0005-itip-handling.patch
new file mode 100644
index 0000000..e3a5e7a
--- /dev/null
+++ b/kolab-webclient/dimp/patches/dimp-1.1.6/0005-itip-handling.patch
@@ -0,0 +1,69 @@
+diff -ur dimp-h3-1.1.6-0004-folders-view/imp.php dimp-h3-1.1.6/imp.php
+--- dimp-h3-1.1.6-0004-folders-view/imp.php	2010-09-27 19:14:30.000000000 +0100
++++ dimp-h3-1.1.6/imp.php	2011-01-10 23:54:42.525945001 +0000
+@@ -730,6 +730,29 @@
+         $result = $prefs->setValue(Util::getPost('pref'), Util::getPost('value'));
+     }
+     break;
++
++case 'iTip':
++    $selection = Util::getPost('selection');
++    $component = Util::getPost('component');
++    $action = str_replace('_', '-', $selection);
++    $_POST['action'] = array($component => $action);
++
++    if (empty($indices)) {
++        break;
++    }
++    $idx_string = _getIdxString($indices);
++
++    /* Parse MIME info and create the body of the message. */
++    require_once IMP_BASE . '/lib/MIME/Contents.php';
++    $imp_contents = &IMP_Contents::singleton($idx_string);
++
++    $cr = !$imp_contents->buildMessage();
++
++    if (is_a($cr, 'PEAR_Error')) {
++        $notification->push($cr, 'horde.error');
++    }
++
++    break;
+ }
+ 
+ // Clear the output buffer that we started above, and log any unexpected
+Only in dimp-h3-1.1.6/: imp.php.orig
+diff -ur dimp-h3-1.1.6-0004-folders-view/js/DimpBase.js dimp-h3-1.1.6/js/DimpBase.js
+--- dimp-h3-1.1.6-0004-folders-view/js/DimpBase.js	2011-01-10 23:52:13.909945003 +0000
++++ dimp-h3-1.1.6/js/DimpBase.js	2011-01-10 23:54:42.527945001 +0000
+@@ -1660,6 +1660,20 @@
+         nf.setStyle({ height: (document.viewport.getHeight() - nf.cumulativeOffset()[1] - 10) + 'px' });
+     },
+ 
++    itip: function(action, index, folder, component)
++    {
++        var args, vs;
++
++	vs = this.viewport.getViewportSelection().search({ imapuid: { equal: [ index ] }, view: { equal: [ folder ] } });
++	if (!vs.size() && folder != this.folder) {
++	    vs = this.viewport.getViewportSelection(folder).search({ imapuid: { equal: [ index ] } });
++	}
++
++	args = this.viewport.addRequestParams({ selection: action, component: component });
++
++	DimpCore.doAction('iTip', args, DimpCore.toUIDArray(vs));
++    },
++
+     /* Flag actions for message list. */
+     flag: function(action, index, folder)
+     {
+diff -ur dimp-h3-1.1.6-0004-folders-view/js/DimpBase.js.orig dimp-h3-1.1.6/js/DimpBase.js.orig
+--- dimp-h3-1.1.6-0004-folders-view/js/DimpBase.js.orig	2011-01-10 23:50:59.238945002 +0000
++++ dimp-h3-1.1.6/js/DimpBase.js.orig	2011-01-10 23:52:13.909945003 +0000
+@@ -1926,6 +1926,7 @@
+         C({ d: $('ctx_folder_rename'), f: function() { this.renameFolder(DimpCore.DMenu.element()); }.bind(this), ns: true });
+         C({ d: $('ctx_folder_empty'), f: function() { if (window.confirm(DIMP.text.empty_folder)) { DimpCore.doAction('EmptyFolder', { folder: DimpCore.DMenu.element().readAttribute('mbox') }, [], this._emptyFolderCallback.bind(this)); } }.bind(this), ns: true });
+         C({ d: $('ctx_folder_delete'), f: function() { if (window.confirm(DIMP.text.delete_folder)) { DimpCore.doAction('DeleteFolder', { folder: DimpCore.DMenu.element().readAttribute('mbox') }, [], this.bcache.get('folderC') || this.bcache.set('folderC', this._folderCallback.bind(this))); } }.bind(this), ns: true });
++        C({ d: $('ctx_folder_rights'), f: function() { this.go('app:horde', DIMP.conf.folder_rights + '&' + $H({ folder: DimpCore.DMenu.element().readAttribute('mbox') }).toQueryString() ) }.bind(this), ns: true });
+         [ 'ctx_folder_seen', 'ctx_folder_unseen' ].each(function(a) {
+             C({ d: $(a), f: function(type) { this.flag(type, null, DimpCore.DMenu.element().readAttribute('mbox')); }.bind(this, a == 'ctx_folder_seen' ? 'allSeen' : 'allUnseen'), ns: true });
+         }, this);
diff --git a/kolab-webclient/dimp/patches/dimp-1.1.6/0006-copy-msgs-with-ctrl.patch b/kolab-webclient/dimp/patches/dimp-1.1.6/0006-copy-msgs-with-ctrl.patch
new file mode 100644
index 0000000..610c11c
--- /dev/null
+++ b/kolab-webclient/dimp/patches/dimp-1.1.6/0006-copy-msgs-with-ctrl.patch
@@ -0,0 +1,629 @@
+diff -ur dimp-h3-1.1.6-0005-itip-handling/js/DimpBase.js dimp-h3-1.1.6/js/DimpBase.js
+--- dimp-h3-1.1.6-0005-itip-handling/js/DimpBase.js	2011-01-10 23:54:42.527945001 +0000
++++ dimp-h3-1.1.6/js/DimpBase.js	2011-01-10 23:56:26.328944998 +0000
+@@ -1175,7 +1175,7 @@
+     },
+ 
+     /* Drag/Drop handler. */
+-    _folderDropHandler: function(drop, drag)
++    _folderDropHandler: function(drop, drag, e)
+     {
+         var dropbase, sel, uids,
+             foldername = drop.readAttribute('mbox'),
+@@ -1198,10 +1198,14 @@
+                 uids = this.viewport.createSelection('domid', drag.id);
+             }
+ 
+-            // Don't allow drag/drop to the current folder.
+-            if (uids.size() && this.folder != foldername) {
+-                this.viewport.updateFlag(uids, 'deletedmsg', true);
+-                DimpCore.doAction('MoveMessage', this.viewport.addRequestParams({ tofld: foldername }), DimpCore.toUIDArray(uids), this.bcache.get('deleteC') || this.bcache.set('deleteC', this._deleteCallback.bind(this)));
++            if (uids.size()) {
++                if (e.ctrlKey) {
++                    DimpCore.doAction('CopyMessage', this.viewport.addRequestParams({ tofld: foldername }), DimpCore.toUIDArray(uids), this.bcache.get('pollFC') || this.bcache.set('pollFC', this._pollFoldersCallback.bind(this)));
++                } else if (this.folder != foldername) {
++                    // Don't allow drag/drop to the current folder.
++                    this.viewport.updateFlag(uids, 'deletedmsg', true);
++                    DimpCore.doAction('MoveMessage', this.viewport.addRequestParams({ tofld: foldername }), DimpCore.toUIDArray(uids), this.bcache.get('deleteC') || this.bcache.set('deleteC', this._deleteCallback.bind(this)));
++                }
+             }
+         }
+     },
+@@ -2073,17 +2077,20 @@
+ 
+ DimpBase._folderDropConfig = {
+     hoverclass: 'dragdrop',
+-    caption: function(drop, drag) {
+-        var d = drag.readAttribute('l'),
++    caption: function(drop, drag, e) {
++        var m,
++            d = drag.readAttribute('l'),
+             ftype = drop.readAttribute('ftype'),
+-            l = drop.readAttribute('l'),
+-            m = DIMP.text.moveto;
++            l = drop.readAttribute('l');
+         if (drop == $('dropbase')) {
+-            return m.replace(/%s/, d).replace(/%s/, DIMP.text.baselevel);
+-        } else if (drag.hasClassName('folder')) {
+-            return (ftype != 'special' && !this.isSubfolder(drag, drop)) ? m.replace(/%s/, d).replace(/%s/, l) : '';
++            return DIMP.text.moveto.replace(/%s/, d).replace(/%s/, DIMP.text.baselevel);
+         } else {
+-            return ftype != 'container' ? m.replace(/%s/, this._dragCaption()).replace(/%s/, l) : '';
++            m = (e.ctrlKey) ? DIMP.text.copyto : DIMP.text.moveto;
++            if (drag.hasClassName('folder')) {
++                return (ftype != 'special' && !this.isSubfolder(drag, drop)) ? m.replace(/%s/, d).replace(/%s/, l) : '';
++            } else {
++                return ftype != 'container' ? m.replace(/%s/, this._dragCaption()).replace(/%s/, l) : '';
++            }
+         }
+     }.bind(DimpBase),
+     onDrop: DimpBase._folderDropHandler.bind(DimpBase)
+diff -ur dimp-h3-1.1.6-0005-itip-handling/js/dragdrop.js dimp-h3-1.1.6/js/dragdrop.js
+--- dimp-h3-1.1.6-0005-itip-handling/js/dragdrop.js	2009-08-07 18:23:40.000000000 +0100
++++ dimp-h3-1.1.6/js/dragdrop.js	2011-01-10 23:56:26.329945003 +0000
+@@ -1 +1,452 @@
+-var DragDrop={Drags:{drags:$H(),register:function(a){if(!this.drags.size()){if(!this.div){this.div=new Element("DIV",{className:a.options.classname}).hide()}$(document.body).insert(this.div)}this.drags.set(a.element.readAttribute("id"),a)},unregister:function(a){if(this.drag==a.element){this.drag.deactivate()}this.drags.unset(a.element.readAttribute("id"));if(!this.drags.size()&&this.div){this.div.remove()}},get_drag:function(a){return this.drags.get(Object.isElement(a)?$(a).readAttribute("id"):a)},activate:function(a){if(this.drag){this.deactivate()}this.drag=a;this.mousemoveE=a._mouseMove.bindAsEventListener(a);this.mouseupE=a._mouseUp.bindAsEventListener(a);document.observe("mousemove",this.mousemoveE);document.observe("mouseup",this.mouseupE)},deactivate:function(){if(this.drag){this.drag=null;document.stopObserving("mousemove",this.mousemoveE);document.stopObserving("mouseup",this.mouseupE)}}},Drops:{drops:$H(),register:function(a){this.drops.set(a.element.readAttribut
 e("id"),a)},unregister:function(a){if(this.drop==a.element){this.drop=null}this.drops.unset(a.element.readAttribute("id"))},get_drop:function(a){return this.drops.get(Object.isElement(a)?$(a).readAttribute("id"):a)}},validDrop:function(a){var b=DragDrop.Drops.drop;return(b&&a&&a!=b.element&&(!b.options.accept.size()||b.options.accept.include(a.tagName)))}},Drag=Class.create({initialize:function(a){this.element=$(a);this.options=Object.extend({caption:"",classname:"drag",constraint:null,ghosting:false,scroll:null,snap:null,threshold:0,onDrag:null,onEnd:null,onStart:null},arguments[1]||{});this.mousedownE=this._mouseDown.bindAsEventListener(this);this.element.observe("mousedown",this.mousedownE);if(this.options.scroll){this.options.scroll=$(this.options.scroll)}DragDrop.Drags.register(this);if(Prototype.Browser.IE){this.element.observe("selectstart",Event.stop)}else{if(Prototype.Browser.Gecko){this.element.setStyle({MozUserSelect:"none"})}}},destroy:function(){this.element.sto
 pObserving("mousedown",this.mousedownE);DragDrop.Drags.unreg!
 ister(th
is)},_mouseDown:function(a){$(document.body).setStyle({cursor:"default"});DragDrop.Drags.activate(this);this.move=0;this.wasDragged=false;this.lastdrag=this.lastcaption=null;if(Object.isFunction(this.options.onStart)){this.options.onStart(this,a)}if(!Prototype.Browser.IE&&!Prototype.Browser.Gecko){a.stop()}},_mouseMove:function(f){var b,c,a,d;if(++this.move<=this.options.threshold){return}this.lastCoord=d=[f.pointerX(),f.pointerY()];if(this.options.ghosting){if(!this.ghost){b=this.element.offsetLeft;c=this.element.offsetTop;this.ghost=$(this.element.cloneNode(true)).writeAttribute("id",null).setOpacity(0.7).clonePosition(this.element,{setLeft:false,setTop:false}).setStyle({left:b+"px",position:"absolute",top:c+"px",zIndex:parseInt(this.element.getStyle("zIndex"))+1});this.element.insert({before:this.ghost});a=this.ghost.viewportOffset();this.ghostOffset=[a[0]-b,a[1]-c]}d[0]-=this.ghostOffset[0];d[1]-=this.ghostOffset[1];switch(this.options.constraint){case"horizontal":d[1]=th
 is.ghost.offsetTop;break;case"vertical":d[0]=this.ghost.offsetLeft;break}if(this.options.snap){d=this.options.snap(d[0],d[1],this.element)}if(this.options.offset){d[0]+=this.options.offset.x;d[1]+=this.options.offset.y}this._setContents(this.ghost,d[0],d[1])}this._onMoveDrag(d);if(Object.isFunction(this.options.onDrag)){this.options.onDrag(this,f)}this.wasDragged=true;if(this.options.scroll){this._onMoveScroll()}},_mouseUp:function(a){var b=DragDrop.Drops.drop;this._stopScrolling();if(this.ghost){this.ghost.remove();this.ghost=null}DragDrop.Drags.div.hide();if(DragDrop.validDrop(this.element)&&Object.isFunction(b.options.onDrop)){b.options.onDrop(b.element,this.element)}DragDrop.Drags.deactivate();if(Object.isFunction(this.options.onEnd)){this.options.onEnd(this,a)}},_onMoveDrag:function(g){var f,c,e,b,a,h=DragDrop.Drops.drop,i=DragDrop.Drags.div;if(h&&h.element!=this.lastdrag){if(DragDrop.validDrop(this.element)){b=h.options.caption;if(b){c=Object.isFunction(b)?b(h.element,
 this.element):b;if(c&&h.options.hoverclass){e=h.options.hove!
 rclass}a
=true}}else{a=true}this.lastdrag=h.element}else{if((!h&&this.lastdrag)||(this.move==(this.options.threshold+1))){a=true;this.lastdrag=null}}if(a){if(!c){f=this.options.caption;c=Object.isFunction(f)?f(this.element):f}this.lastcaption=c;i.update(c).writeAttribute({className:e||this.options.classname});if(c.empty()){i.hide()}}if(!this.lastcaption.empty()){this._setContents(i,g[0]+15,g[1]+(this.ghost?(this.ghost.getHeight()+5):5))}},_onMoveScroll:function(){this._stopScrolling();var e,d,b,a=this.options.scroll,c=a.getDimensions();if(a.scrollHeight==c.height){return}e=document.viewport.getScrollOffsets();d=a.viewportOffset(),b=[0,0];d[0]+=a.scrollLeft+e.left;d[2]=d[0]+c.width;if(this.lastCoord[0]>d[2]||this.lastCoord[0]<d[0]){return}d[1]+=a.scrollTop+e.top;d[3]=d[1]+c.height;if(this.lastCoord[1]<d[1]){b[1]=this.lastCoord[1]-d[1]}if(this.lastCoord[1]>d[3]){b[1]=this.lastCoord[1]-d[3]}if(b[0]||b[1]){this.lastScrolled=new Date();this.scrollInterval=setInterval(this._scroll.bind(this
 ,b[0]*15,b[1]*15),10)}},_stopScrolling:function(){if(this.scrollInterval){clearInterval(this.scrollInterval);this.scrollInterval=null}},_scroll:function(a,e){var c=new Date(),d=c-this.lastScrolled,b=this.options.scroll;this.lastScrolled=c;b.scrollTop+=e*d/1000},_setContents:function(c,a,e){var d=document.viewport.getDimensions(),b=c.getDimensions();if((a+b.width>d.width)||(e+b.height>d.height)){c.hide()}else{c.setStyle({left:a+"px",top:e+"px"}).show()}}}),Drop=Class.create({initialize:function(a){this.element=$(a);this.options=Object.extend({accept:[],caption:"",hoverclass:"",onDrop:null,onOut:null,onOver:null},arguments[1]||{});this.mouseoverE=this._mouseOver.bindAsEventListener(this);this.mouseoutE=this._mouseOut.bindAsEventListener(this);this.element.observe("mouseover",this.mouseoverE);this.element.observe("mouseout",this.mouseoutE);DragDrop.Drops.register(this)},destroy:function(){this.element.stopObserving("mouseover",this.mouseoverE);this.element.stopObserving("mouseo
 ut",this.mouseoutE);DragDrop.Drops.unregister(this)},_mouseO!
 ver:func
tion(a){if(DragDrop.Drags.drag){DragDrop.Drops.drop=this;if(Object.isFunction(this.options.onOver)){this.options.onOver(this.element,DragDrop.Drags.drag)}}},_mouseOut:function(a){if(Object.isFunction(this.options.onOut)){this.options.onOut(this.element,DragDrop.Drags.drag)}DragDrop.Drops.drop=null}});
+\ No newline at end of file
++/**
++ * dragdrop.js - A minimalist library to handle drag/drop actions.
++ * Requires prototype.js 1.6.0.2+
++ *
++ * Adapted from SkyByte.js/SkyByteDD.js v1.0-beta, May 17 2007
++ *   (c) 2007 Aleksandras Ilarionovas (Alex)
++ *   http://www.skybyte.net/scripts/
++ *
++ * Scrolling and ghosting code adapted from script.aculo.us dragdrop.js v1.8.0
++ *   (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
++ *   (c) 2005-2007 Sammi Williams (http://www.oriontransfer.co.nz, sammi at oriontransfer.co.nz)
++ *
++ * The original scripts were freely distributable under the terms of an
++ * MIT-style license.
++ *
++ * Usage:
++ *   new Drag(element, {
++ *       classname: '',           // Class name of the drag element
++ *       caption: '',             // Either string or function to set caption
++ *                                // on mouse move
++ *       ghosting: false,         // Show ghost outline when dragging.
++ *       offset: { x:0, y:0 },    // An offset to apply to ghosted elements.
++ *       scroll: element,         // Scroll this element when above/below.
++ *                                // Only working for vertical elements
++ *       snap: null,              // If ghosting, snap allows to specify
++ *                                // coords at which the ghosted image will
++ *                                // "snap" into place.
++ *       threshold: 0,            // Move threshold
++ *       // For the following functions, d = drop element, e = event object
++ *       onStart: function(d,e),  // A function to run on mousedown
++ *       onDrag: function(d,e),   // A function to run on mousemove
++ *       onEnd: function(d,e)     // A function to run on mouseup
++ *   });
++ *
++ *   new Drop(element, {
++ *       accept: [],           // Accept filter by tag name(s) or leave empty
++ *                             // to accept all tags
++ *       caption: '',          // Either string or function to set caption on
++ *                             // mouse over
++ *       hoverclass: '',       // Change the drag element to this class when
++ *                             // hovering over an element.
++ *       onDrop: function(drop,drag)  // Function fired when mouse button
++ *                                    // released (a/k/a a drop event)
++ *       onOver: function(drop,drag)  // Function fired when mouse over zone
++ *       onOut: function(drop,drag)   // Function fired when mouse leaves the
++ *                                    // zone
++ *  });
++ *
++ * $Horde
++ *
++ * @author Michael Slusarz <slusarz at curecanti.org>
++ */
++
++var DragDrop = {
++    Drags: {
++        drags: $H(),
++
++        register: function(obj)
++        {
++            if (!this.drags.size()) {
++                if (!this.div) {
++                    this.div = new Element('DIV', { className: obj.options.classname }).hide();
++                }
++                $(document.body).insert(this.div);
++            }
++
++            this.drags.set(obj.element.readAttribute('id'), obj);
++        },
++
++        unregister: function(obj)
++        {
++            if (this.drag == obj.element) {
++                this.drag.deactivate();
++            }
++
++            this.drags.unset(obj.element.readAttribute('id'));
++
++            if (!this.drags.size() && this.div) {
++                this.div.remove();
++            }
++        },
++
++        get_drag: function(el)
++        {
++            return this.drags.get(Object.isElement(el) ? $(el).readAttribute('id') : el);
++        },
++
++        activate: function(drag)
++        {
++            if (this.drag) {
++                this.deactivate();
++            }
++            this.drag = drag;
++            this.mousemoveE = drag._mouseMove.bindAsEventListener(drag);
++            this.mouseupE = drag._mouseUp.bindAsEventListener(drag);
++            document.observe('mousemove', this.mousemoveE);
++            document.observe('mouseup', this.mouseupE);
++        },
++
++        deactivate: function()
++        {
++            if (this.drag) {
++                this.drag = null;
++                document.stopObserving('mousemove', this.mousemoveE);
++                document.stopObserving('mouseup', this.mouseupE);
++            }
++        }
++    },
++
++    Drops: {
++        drops: $H(),
++
++        register: function(obj)
++        {
++            this.drops.set(obj.element.readAttribute('id'), obj);
++        },
++
++        unregister: function(obj)
++        {
++            if (this.drop == obj.element) {
++                this.drop = null;
++            }
++
++            this.drops.unset(obj.element.readAttribute('id'));
++        },
++
++        get_drop: function(el)
++        {
++            return this.drops.get(Object.isElement(el) ? $(el).readAttribute('id') : el);
++        }
++    },
++
++    validDrop: function(el)
++    {
++        var d = DragDrop.Drops.drop;
++        return (d &&
++                el &&
++                el != d.element &&
++                (!d.options.accept.size() ||
++                 d.options.accept.include(el.tagName)));
++    }
++},
++
++Drag = Class.create({
++
++    initialize: function(el) {
++        this.element = $(el);
++        this.options = Object.extend({
++            caption: '',
++            classname: 'drag',
++            constraint: null,
++            ghosting: false,
++            scroll: null,
++            snap: null,
++            threshold: 0,
++            onDrag: null,
++            onEnd: null,
++            onStart: null
++        }, arguments[1] || {});
++        this.mousedownE = this._mouseDown.bindAsEventListener(this);
++        this.element.observe('mousedown', this.mousedownE);
++        if (this.options.scroll) {
++            this.options.scroll = $(this.options.scroll);
++        }
++        DragDrop.Drags.register(this);
++
++        // Disable text selection.
++        // See: http://ajaxcookbook.org/disable-text-selection/
++        // Stopping the event on mousedown works on all browsers, but avoid
++        // that if possible because it will prevent any event handlers further
++        // up the DOM tree from firing.
++        if (Prototype.Browser.IE) {
++            this.element.observe('selectstart', Event.stop);
++        } else if (Prototype.Browser.Gecko) {
++            this.element.setStyle({ MozUserSelect: 'none' });
++        }
++    },
++
++    destroy: function()
++    {
++        this.element.stopObserving('mousedown', this.mousedownE);
++        DragDrop.Drags.unregister(this);
++    },
++
++    _mouseDown: function(e)
++    {
++        $(document.body).setStyle({ cursor: 'default' });
++        DragDrop.Drags.activate(this);
++        this.move = 0;
++        this.wasDragged = false;
++        this.lastcaption = null;
++
++        if (Object.isFunction(this.options.onStart)) {
++            this.options.onStart(this, e);
++        }
++
++        if (!Prototype.Browser.IE && !Prototype.Browser.Gecko) {
++            e.stop();
++        }
++    },
++
++    _mouseMove: function(e)
++    {
++        var oleft, otop, vo, xy;
++
++        if (++this.move <= this.options.threshold) {
++            return;
++        }
++
++        this.lastCoord = xy = [ e.pointerX(), e.pointerY() ];
++
++        if (this.options.ghosting) {
++            if (!this.ghost) {
++                oleft = this.element.offsetLeft;
++                otop = this.element.offsetTop;
++                this.ghost = $(this.element.cloneNode(true)).writeAttribute('id', null).setOpacity(0.7).clonePosition(this.element, { setLeft: false, setTop: false }).setStyle({ left: oleft + 'px', position: 'absolute', top: otop + 'px', zIndex: parseInt(this.element.getStyle('zIndex')) + 1 });
++                this.element.insert({ before: this.ghost });
++                vo = this.ghost.viewportOffset();
++                this.ghostOffset = [ vo[0] - oleft, vo[1] - otop ];
++            }
++
++            xy[0] -= this.ghostOffset[0];
++            xy[1] -= this.ghostOffset[1];
++
++            switch (this.options.constraint) {
++            case 'horizontal':
++                xy[1] = this.ghost.offsetTop;
++                break;
++
++            case 'vertical':
++                xy[0] = this.ghost.offsetLeft;
++                break;
++            }
++
++            if (this.options.snap) {
++                xy = this.options.snap(xy[0], xy[1], this.element);
++            }
++
++            if (this.options.offset) {
++                xy[0] += this.options.offset.x;
++                xy[1] += this.options.offset.y;
++            }
++
++            this._setContents(this.ghost, xy[0], xy[1]);
++        }
++
++        this._onMoveDrag(xy, e);
++
++        if (Object.isFunction(this.options.onDrag)) {
++            this.options.onDrag(this, e);
++        }
++
++        this.wasDragged = true;
++
++        if (this.options.scroll) {
++            this._onMoveScroll();
++        }
++    },
++
++    _mouseUp: function(e)
++    {
++        var d = DragDrop.Drops.drop;
++
++        this._stopScrolling();
++
++        if (this.ghost) {
++            this.ghost.remove();
++            this.ghost = null;
++        }
++        DragDrop.Drags.div.hide();
++
++        if (DragDrop.validDrop(this.element) &&
++            Object.isFunction(d.options.onDrop)) {
++            d.options.onDrop(d.element, this.element, e);
++        }
++
++        DragDrop.Drags.deactivate();
++
++        if (Object.isFunction(this.options.onEnd)) {
++            this.options.onEnd(this, e);
++        }
++    },
++
++    _onMoveDrag: function(xy, e)
++    {
++        var c_opt, caption, cname, d_cap,
++            d = DragDrop.Drops.drop,
++            div = DragDrop.Drags.div,
++            d_update = true;
++
++        if (d && DragDrop.validDrop(this.element)) {
++            d_cap = d.options.caption;
++            if (d_cap) {
++                caption = Object.isFunction(d_cap) ? d_cap(d.element, this.element, e) : d_cap;
++                if (caption && d.options.hoverclass) {
++                    cname = d.options.hoverclass;
++                }
++            } else {
++                d_update = false;
++            }
++        }
++
++        if (d_update) {
++            if (!caption) {
++                c_opt = this.options.caption;
++                caption = Object.isFunction(c_opt) ? c_opt(this.element) : c_opt;
++            }
++            if (caption != this.lastcaption) {
++                this.lastcaption = caption;
++                div.update(caption).writeAttribute({ className: cname || this.options.classname });
++                if (caption.empty()) {
++                    div.hide();
++                }
++            }
++        }
++
++        if (!this.lastcaption.empty()) {
++            this._setContents(div, xy[0] + 15, xy[1] + (this.ghost ? (this.ghost.getHeight() + 5) : 5));
++        }
++    },
++
++    _onMoveScroll: function()
++    {
++        this._stopScrolling();
++
++        var delta, p, speed,
++            s = this.options.scroll,
++            dim = s.getDimensions();
++
++        // No need to scroll if element is not current scrolling.
++        if (s.scrollHeight == dim.height) {
++            return;
++        }
++
++        delta = document.viewport.getScrollOffsets();
++        p = s.viewportOffset(),
++        speed = [ 0, 0 ];
++
++        p[0] += s.scrollLeft + delta.left;
++        p[2] = p[0] + dim.width;
++
++        // Only scroll if directly above/below element
++        if (this.lastCoord[0] > p[2] ||
++            this.lastCoord[0] < p[0]) {
++            return;
++        }
++
++        p[1] += s.scrollTop + delta.top;
++        p[3] = p[1] + dim.height;
++
++        // Left scroll
++        //if (this.lastCoord[0] < p[0]) {
++        //    speed[0] = this.lastCoord[0] - p[0];
++        //}
++        // Top scroll
++        if (this.lastCoord[1] < p[1]) {
++            speed[1] = this.lastCoord[1] - p[1];
++        }
++        // Scroll right
++        //if (this.lastCoord[0] > p[2]) {
++        //    speed[0] = this.lastCoord[0] - p[2];
++        //}
++        // Scroll left
++        if (this.lastCoord[1] > p[3]) {
++            speed[1] = this.lastCoord[1] - p[3];
++        }
++
++        if (speed[0] || speed[1]) {
++            this.lastScrolled = new Date();
++            this.scrollInterval = setInterval(this._scroll.bind(this, speed[0] * 15, speed[1] * 15), 10);
++        }
++    },
++
++    _stopScrolling: function()
++    {
++        if (this.scrollInterval) {
++            clearInterval(this.scrollInterval);
++            this.scrollInterval = null;
++        }
++    },
++
++    _scroll: function(x, y)
++    {
++        var current = new Date(),
++            delta = current - this.lastScrolled,
++            s = this.options.scroll;
++        this.lastScrolled = current;
++
++        //s.scrollLeft += x * delta / 1000;
++        s.scrollTop += y * delta / 1000;
++    },
++
++    _setContents: function(elt, x, y)
++    {
++        var d_pos = document.viewport.getDimensions(),
++            e_pos = elt.getDimensions();
++
++        if ((x + e_pos.width > d_pos.width) ||
++            (y + e_pos.height > d_pos.height)) {
++            elt.hide();
++        } else {
++            elt.setStyle({ left: x + 'px', top: y + 'px' }).show();
++        }
++    }
++
++}),
++
++Drop = Class.create({
++
++    initialize: function(el)
++    {
++        this.element = $(el);
++        this.options = Object.extend({
++            accept: [],
++            caption: '',
++            hoverclass: '',
++            onDrop: null,
++            onOut: null,
++            onOver: null
++        }, arguments[1] || {});
++        this.mouseoverE = this._mouseOver.bindAsEventListener(this);
++        this.mouseoutE = this._mouseOut.bindAsEventListener(this);
++        this.element.observe('mouseover', this.mouseoverE);
++        this.element.observe('mouseout', this.mouseoutE);
++        DragDrop.Drops.register(this);
++    },
++
++    destroy: function()
++    {
++        this.element.stopObserving('mouseover', this.mouseoverE);
++        this.element.stopObserving('mouseout', this.mouseoutE);
++        DragDrop.Drops.unregister(this);
++    },
++
++    _mouseOver: function(e)
++    {
++        if (DragDrop.Drags.drag) {
++            DragDrop.Drops.drop = this;
++            if (Object.isFunction(this.options.onOver)) {
++                this.options.onOver(this.element, DragDrop.Drags.drag);
++            }
++        }
++    },
++
++    _mouseOut: function(e)
++    {
++        if (Object.isFunction(this.options.onOut)) {
++            this.options.onOut(this.element, DragDrop.Drags.drag);
++        }
++        DragDrop.Drops.drop = null;
++    }
++});
+diff -ur dimp-h3-1.1.6-0005-itip-handling/js/src/dragdrop.js dimp-h3-1.1.6/js/src/dragdrop.js
+--- dimp-h3-1.1.6-0005-itip-handling/js/src/dragdrop.js	2008-08-04 19:58:11.000000000 +0100
++++ dimp-h3-1.1.6/js/src/dragdrop.js	2011-01-10 23:56:26.330945006 +0000
+@@ -188,7 +188,7 @@
+         DragDrop.Drags.activate(this);
+         this.move = 0;
+         this.wasDragged = false;
+-        this.lastdrag = this.lastcaption = null;
++        this.lastcaption = null;
+ 
+         if (Object.isFunction(this.options.onStart)) {
+             this.options.onStart(this, e);
+@@ -244,7 +244,7 @@
+             this._setContents(this.ghost, xy[0], xy[1]);
+         }
+ 
+-        this._onMoveDrag(xy);
++        this._onMoveDrag(xy, e);
+ 
+         if (Object.isFunction(this.options.onDrag)) {
+             this.options.onDrag(this, e);
+@@ -271,7 +271,7 @@
+ 
+         if (DragDrop.validDrop(this.element) &&
+             Object.isFunction(d.options.onDrop)) {
+-            d.options.onDrop(d.element, this.element);
++            d.options.onDrop(d.element, this.element, e);
+         }
+ 
+         DragDrop.Drags.deactivate();
+@@ -281,30 +281,23 @@
+         }
+     },
+ 
+-    _onMoveDrag: function(xy)
++    _onMoveDrag: function(xy, e)
+     {
+-        var c_opt, caption, cname, d_cap, d_update,
++        var c_opt, caption, cname, d_cap,
+             d = DragDrop.Drops.drop,
+-            div = DragDrop.Drags.div;
++            div = DragDrop.Drags.div,
++            d_update = true;
+ 
+-        if (d && d.element != this.lastdrag) {
+-            if (DragDrop.validDrop(this.element)) {
+-                d_cap = d.options.caption;
+-                if (d_cap) {
+-                    caption = Object.isFunction(d_cap) ? d_cap(d.element, this.element) : d_cap;
+-                    if (caption && d.options.hoverclass) {
+-                        cname = d.options.hoverclass;
+-                    }
+-                    d_update = true;
++        if (d && DragDrop.validDrop(this.element)) {
++            d_cap = d.options.caption;
++            if (d_cap) {
++                caption = Object.isFunction(d_cap) ? d_cap(d.element, this.element, e) : d_cap;
++                if (caption && d.options.hoverclass) {
++                    cname = d.options.hoverclass;
+                 }
+             } else {
+-                d_update = true;
++                d_update = false;
+             }
+-            this.lastdrag = d.element;
+-        } else if ((!d && this.lastdrag) ||
+-                   (this.move == (this.options.threshold + 1))) {
+-            d_update = true;
+-            this.lastdrag = null;
+         }
+ 
+         if (d_update) {
+@@ -312,10 +305,12 @@
+                 c_opt = this.options.caption;
+                 caption = Object.isFunction(c_opt) ? c_opt(this.element) : c_opt;
+             }
+-            this.lastcaption = caption;
+-            div.update(caption).writeAttribute({ className: cname || this.options.classname });
+-            if (caption.empty()) {
+-                div.hide();
++            if (caption != this.lastcaption) {
++                this.lastcaption = caption;
++                div.update(caption).writeAttribute({ className: cname || this.options.classname });
++                if (caption.empty()) {
++                    div.hide();
++                }
+             }
+         }
+ 
+diff -ur dimp-h3-1.1.6-0005-itip-handling/lib/DIMP.php dimp-h3-1.1.6/lib/DIMP.php
+--- dimp-h3-1.1.6-0005-itip-handling/lib/DIMP.php	2011-01-10 23:52:13.910945003 +0000
++++ dimp-h3-1.1.6/lib/DIMP.php	2011-01-10 23:56:26.330945006 +0000
+@@ -219,6 +219,7 @@
+             'showtext' => _("Show Quoted Text"),
+             'lines' => _("lines"),
+             'ok' => _("Ok"),
++            'copyto' => _("Copy %s to %s"),
+             'moveto' => _("Move %s to %s"),
+             'baselevel' => _("base level of the folder tree"),
+             'cancel' => _("Cancel"),
+diff -ur dimp-h3-1.1.6-0005-itip-handling/lib/DIMP.php.orig dimp-h3-1.1.6/lib/DIMP.php.orig
+--- dimp-h3-1.1.6-0005-itip-handling/lib/DIMP.php.orig	2011-01-10 23:49:33.897945000 +0000
++++ dimp-h3-1.1.6/lib/DIMP.php.orig	2011-01-10 23:52:13.910945003 +0000
+@@ -166,6 +166,7 @@
+             'message_url' => Horde::url($dimp_webroot . '/message.php'),
+             'compose_url' => Horde::url($dimp_webroot . '/compose.php'),
+             'prefs_url' => str_replace('&', '&', Horde::getServiceLink('options', 'dimp')),
++	    'folder_rights' => Util::addParameter(Horde::url($registry->get('webroot', 'imp') . '/acl.php', true), array('app' => 'imp', 'group'=> 'acl'), null, false),
+ 
+             'sortthread' => SORTTHREAD,
+             'sortdate' => SORTDATE,
diff --git a/kolab-webclient/dimp/patches/dimp-1.1.6/series b/kolab-webclient/dimp/patches/dimp-1.1.6/series
index ecb3f6d..56ab895 100644
--- a/kolab-webclient/dimp/patches/dimp-1.1.6/series
+++ b/kolab-webclient/dimp/patches/dimp-1.1.6/series
@@ -1,6 +1,7 @@
-t_dimp_H_MS_FixBrokenFolderImages.diff
-t_dimp_H_BL_CloseContextMenu.diff
-t_dimp_H_GW_AclView.diff
-t_dimp_H_GW_FoldersView.diff
-t_dimp_HK_GW_ItipHandling.diff
-t_dimp_H_MS_CopyMessagesWithCtrl.diff
\ No newline at end of file
+0001-fix-broken-folder-images.patch
+0002-close-context-menu.patch
+0003-acl-view.patch
+0004-folders-view.patch
+0005-itip-handling.patch
+0006-copy-msgs-with-ctrl.patch
+
diff --git a/kolab-webclient/dimp/patches/dimp-1.1.6/t_dimp_HK_GW_ItipHandling.diff b/kolab-webclient/dimp/patches/dimp-1.1.6/t_dimp_HK_GW_ItipHandling.diff
deleted file mode 100644
index b20c9f0..0000000
--- a/kolab-webclient/dimp/patches/dimp-1.1.6/t_dimp_HK_GW_ItipHandling.diff
+++ /dev/null
@@ -1,72 +0,0 @@
-From: Gunnar Wrobel <p at rdus.de>
-Subject: [PATCH] t/dimp/HK/GW/ItipHandling
-
-Allow handling iTip messages in dimp.
-
-Signed-off-by: Gunnar Wrobel <p at rdus.de>
-
----
- imp.php                 |   23 +++++++
- js/DimpBase.js          |   14 ++++
- 2 files changed, 108 insertions(+), 27 deletions(-)
-
-diff --git a/imp.php b/imp.php
-index f8b9b5c..70264fe 100644
---- a/imp.php
-+++ b/imp.php
-@@ -710,6 +710,29 @@ case 'SendMDN':
-     $imp_ui = new IMP_UI_Message();
-     $imp_ui->MDNCheck($ob->header, true);
-     break;
-+
-+case 'iTip':
-+    $selection = Util::getPost('selection');
-+    $component = Util::getPost('component');
-+    $action = str_replace('_', '-', $selection);
-+    $_POST['action'] = array($component => $action);
-+
-+    if (empty($indices)) {
-+        break;
-+    }
-+    $idx_string = _getIdxString($indices);
-+
-+    /* Parse MIME info and create the body of the message. */
-+    require_once IMP_BASE . '/lib/MIME/Contents.php';
-+    $imp_contents = &IMP_Contents::singleton($idx_string);
-+
-+    $cr = !$imp_contents->buildMessage();
-+
-+    if (is_a($cr, 'PEAR_Error')) {
-+        $notification->push($cr, 'horde.error');
-+    }
-+
-+    break;
- }
- 
- // Clear the output buffer that we started above, and log any unexpected
-diff --git a/js/DimpBase.js b/js/DimpBase.js
-index 96cd917..39a728b 100644
---- a/js/DimpBase.js
-+++ b/js/DimpBase.js
-@@ -1663,6 +1663,20 @@ var DimpBase = {
-         nf.setStyle({ height: (document.viewport.getHeight() - nf.cumulativeOffset()[1] - 10) + 'px' });
-     },
- 
-+    itip: function(action, index, folder, component)
-+    {
-+        var args, vs;
-+
-+	vs = this.viewport.getViewportSelection().search({ imapuid: { equal: [ index ] }, view: { equal: [ folder ] } });
-+	if (!vs.size() && folder != this.folder) {
-+	    vs = this.viewport.getViewportSelection(folder).search({ imapuid: { equal: [ index ] } });
-+	}
-+
-+	args = this.viewport.addRequestParams({ selection: action, component: component });
-+
-+	DimpCore.doAction('iTip', args, DimpCore.toUIDArray(vs));
-+    },
-+
-     /* Flag actions for message list. */
-     flag: function(action, index, folder)
-     {
-
diff --git a/kolab-webclient/dimp/patches/dimp-1.1.6/t_dimp_H_BL_CloseContextMenu.diff b/kolab-webclient/dimp/patches/dimp-1.1.6/t_dimp_H_BL_CloseContextMenu.diff
deleted file mode 100644
index e7c40b0..0000000
--- a/kolab-webclient/dimp/patches/dimp-1.1.6/t_dimp_H_BL_CloseContextMenu.diff
+++ /dev/null
@@ -1,45 +0,0 @@
-From: Gunnar Wrobel <p at rdus.de>
-Subject: [PATCH] t/dimp/H/BL/CloseContextMenu
-
-Close the context menu when clicking into the Dimp menu.
-
-Provided by Boris Lorbeer <B.Lorbeer at science-computing.de>
-
-Signed-off-by: Gunnar Wrobel <p at rdus.de>
-
----
- js/DimpBase.js  |    3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
-diff --git a/js/DimpBase.js b/js/DimpBase.js
-index c4eb9f4..d90f09b 100644
---- a/js/DimpBase.js
-+++ b/js/DimpBase.js
-@@ -1507,6 +1507,7 @@ var DimpBase = {
- 
-                 case 'folder':
-                 case 'special':
-+                    DimpCore.DMenu.close();
-                     e.stop();
-                     return this.go('folder:' + li.readAttribute('mbox'));
-                     break;
-@@ -1903,7 +1904,7 @@ var DimpBase = {
-         tmp = $('applicationfolders');
-         if (tmp) {
-             tmp.select('ul li.custom a').each(function(s) {
--                C({ d: s, f: this.go.bind(this, 'app:' + s.readAttribute('app')) });
-+                C({ d: s, f: function(data){DimpCore.DMenu.close(); this.go('app:' + s.readAttribute('app'), data)}.bind(this) });
-             }, this);
-         }
- 
--- 
-tg: (19ee6e6..) t/dimp/H/BL/CloseContextMenu (depends on: t/kronolith/HK/GW/AnonymousiCalDownload)
--- 
-TOPGIT patch commit log
-=======================
-
-commit b4b3190a4fb88e1843ff86adde4897dea21046db
-Author: Gunnar Wrobel <p at rdus.de>
-Date:   Mon Jul 20 09:39:24 2009 +0200
-
-    Close the context menu when clicking into the Dimp menu.
diff --git a/kolab-webclient/dimp/patches/dimp-1.1.6/t_dimp_H_GW_AclView.diff b/kolab-webclient/dimp/patches/dimp-1.1.6/t_dimp_H_GW_AclView.diff
deleted file mode 100644
index c3da779..0000000
--- a/kolab-webclient/dimp/patches/dimp-1.1.6/t_dimp_H_GW_AclView.diff
+++ /dev/null
@@ -1,107 +0,0 @@
-From: Gunnar Wrobel <p at rdus.de>
-Subject: [PATCH] t/dimp/H/GW/AclView
-
-Provide a possibility to edit IMAP folder acls within DIMP.
-
-kolab/issue3455 (There is no convenient/dimp-like way in dimp to set folder acls)
-https://www.intevation.de/roundup/kolab/issue3455
-
-[#8060] Additional entry in the folder popup to set IMAP ACLs
-http://bugs.horde.org/ticket/8060
-
-Signed-off-by: Gunnar Wrobel <p at rdus.de>
-
----
- js/DimpBase.js                  |    1 +
- lib/DIMP.php                    |    1 +
- .../dimp/locale/de_DE/LC_MESSAGES/dimp.mo          |  Bin 168731 -> 168778 bytes
- po/de_DE.po                     |    3 +++
- templates/index/index.inc       |    1 +
- 7 files changed, 29 insertions(+), 2 deletions(-)
-
-diff --git a/js/DimpBase.js b/js/DimpBase.js
-index 39a728b..c4eb9f4 100644
---- a/js/DimpBase.js
-+++ b/js/DimpBase.js
-@@ -1941,6 +1941,7 @@ var DimpBase = {
-         C({ d: $('ctx_folder_rename'), f: function() { this.renameFolder(DimpCore.DMenu.element()); }.bind(this), ns: true });
-         C({ d: $('ctx_folder_empty'), f: function() { if (window.confirm(DIMP.text.empty_folder)) { DimpCore.doAction('EmptyFolder', { folder: DimpCore.DMenu.element().readAttribute('mbox') }, [], this._emptyFolderCallback.bind(this)); } }.bind(this), ns: true });
-         C({ d: $('ctx_folder_delete'), f: function() { if (window.confirm(DIMP.text.delete_folder)) { DimpCore.doAction('DeleteFolder', { folder: DimpCore.DMenu.element().readAttribute('mbox') }, [], this.bcache.get('folderC') || this.bcache.set('folderC', this._folderCallback.bind(this))); } }.bind(this), ns: true });
-+        C({ d: $('ctx_folder_rights'), f: function() { this.go('app:horde', DIMP.conf.folder_rights + '&' + $H({ folder: DimpCore.DMenu.element().readAttribute('mbox') }).toQueryString() ) }.bind(this), ns: true });
-         [ 'ctx_folder_seen', 'ctx_folder_unseen' ].each(function(a) {
-             C({ d: $(a), f: function(type) { this.flag(type, null, DimpCore.DMenu.element().readAttribute('mbox')); }.bind(this, a == 'ctx_folder_seen' ? 'allSeen' : 'allUnseen'), ns: true });
-         }, this);
-diff --git a/lib/DIMP.php b/lib/DIMP.php
-index 0aa3b78..92a1e55 100644
---- a/lib/DIMP.php
-+++ b/lib/DIMP.php
-@@ -145,6 +145,7 @@ class DIMP {
-             'message_url' => Horde::url($dimp_webroot . '/message.php'),
-             'compose_url' => Horde::url($dimp_webroot . '/compose.php'),
-             'prefs_url' => str_replace('&', '&', Horde::getServiceLink('options', 'dimp')),
-+	    'folder_rights' => Util::addParameter(Horde::url($registry->get('webroot', 'imp') . '/acl.php', true), array('app' => 'imp', 'group'=> 'acl'), null, false),
- 
-             'sortthread' => SORTTHREAD,
-             'sortdate' => SORTDATE,
-diff --git a/locale/de_DE/LC_MESSAGES/dimp.mo b/locale/de_DE/LC_MESSAGES/dimp.mo
-index 2f1c11c..973776f 100644
-Binary files a/locale/de_DE/LC_MESSAGES/dimp.mo and b/locale/de_DE/LC_MESSAGES/dimp.mo differ
-diff --git a/po/de_DE.po b/po/de_DE.po
-index a536db6..0486297 100644
---- a/po/de_DE.po
-+++ b/po/de_DE.po
-@@ -791,3 +791,6 @@ msgstr "entfernen"
- #: lib/DIMP.php:191
- msgid "results found"
- msgstr "Ergebnisse gefunden"
-+
-+msgid "Share Folder"
-+msgstr "Berechtigungen"
-diff --git a/templates/index/index.inc b/templates/index/index.inc
-index 21939e0..7c02fe7 100644
---- a/templates/index/index.inc
-+++ b/templates/index/index.inc
-@@ -323,6 +323,7 @@ function _createDA($text, $image, $id = null, $class = '', $show_text = true)
-  <a id="ctx_folder_rename"><?php echo $folder_edit . _("Rename Folder") ?></a>
-  <a id="ctx_folder_empty"><?php echo $delete . _("Empty Folder") ?></a>
-  <a id="ctx_folder_delete"><?php echo Horde::img('folders/folder_delete.png') . _("Delete Folder") ?></a>
-+ <a id="ctx_folder_rights"><?php echo Horde::img('folders/folder.png') . _("Share Folder") ?></a>
-  <div id="ctx_folder_seen_sep" class="sep"></div>
-  <a id="ctx_folder_seen"><?php echo $mailseen . _("Mark all as Read") ?></a>
-  <a id="ctx_folder_unseen"><?php echo $mailunseen . _("Mark all as New") ?></a>
-
--- 
-tg: (f251c16..) t/dimp/H/GW/AclView (depends on: t/dimp/H/GW/FoldersView)
--- 
-TOPGIT patch commit log
-=======================
-
-commit e9630629c7479c73d3eb156f00544c34e95f0597
-Author: Gunnar Wrobel <p at rdus.de>
-Date:   Mon Jul 20 09:36:01 2009 +0200
-
-    Fix translation and improve header.
-
-commit 57041c04c322dd7dc57da5b171923b7ab000ec0a
-Author: Gunnar Wrobel <p at rdus.de>
-Date:   Sun Jun 21 23:58:30 2009 +0200
-
-    German translation.
-
-commit cac1482cec6c96a8a1d7fb7c0e8c2433877728f5
-Author: Gunnar Wrobel <p at rdus.de>
-Date:   Fri Mar 13 12:04:03 2009 +0000
-
-    Complete the patch description.
-
-commit 7a349ad9da06264378e84e54d7424f5dc78a9154
-Author: Gunnar Wrobel <p at rdus.de>
-Date:   Fri Mar 13 12:00:43 2009 +0000
-
-    Reduce the functionality of the ACL view when calling from DIMP. In addition add the call to the acl settings page within the folder context menu.
-
-commit 2fdc4d0fcd6e4956129f6ec11501112568b99c6d
-Author: Gunnar Wrobel <p at rdus.de>
-Date:   Sun Mar 8 19:59:30 2009 +0000
-
-    Completed a draft.
diff --git a/kolab-webclient/dimp/patches/dimp-1.1.6/t_dimp_H_GW_FoldersView.diff b/kolab-webclient/dimp/patches/dimp-1.1.6/t_dimp_H_GW_FoldersView.diff
deleted file mode 100644
index 24a486d..0000000
--- a/kolab-webclient/dimp/patches/dimp-1.1.6/t_dimp_H_GW_FoldersView.diff
+++ /dev/null
@@ -1,100 +0,0 @@
-From: Gunnar Wrobel <p at rdus.de>
-Subject: [PATCH] t/dimp/H/GW/FoldersView
-
-Provide a folders menu for dimp.
-
-kolab/issue3456 (There is no view in dimp that allows folder subscription)
-https://www.intevation.de/roundup/kolab/issue3456
-
-[#8059] DIMP provides no view to subscribe/unsubscribe to folders
-http://bugs.horde.org/ticket/8059
-
-Signed-off-by: Gunnar Wrobel <p at rdus.de>
-
----
- config/menu.php               |    9 ++++++++-
- po/de_DE.po                   |    3 +++
- 2 files changed, 25 insertions(+), 6 deletions(-)
-
-diff --git a/config/menu.php b/config/menu.php
-index 0c6ebe9..b5e0a5c 100644
---- a/config/menu.php.dist
-+++ b/config/menu.php.dist
-@@ -28,3 +28,14 @@
- //         'text' => 'Say Hi!',
- //         'icon' => $GLOBALS['registry']->getImageDir('horde') . '/horde.png'),
- // );
-+
-+// Load configuration files in .d directory
-+$directory = dirname(__FILE__) . '/menu.d';
-+if (file_exists($directory) && is_dir($directory)) {
-+    $sub_files = glob("$directory/*.php");
-+    if ($sub_files) {
-+        foreach ($sub_files as $sub_file) {
-+            require_once $sub_file;
-+        }
-+    }
-+ }
-
-diff --git a/po/de_DE.po b/po/de_DE.po
-index 65e8824..a536db6 100644
---- a/po/de_DE.po
-+++ b/po/de_DE.po
-@@ -16,6 +16,9 @@ msgstr ""
- "Content-Transfer-Encoding: 8bit\n"
- "Plural-Forms: nplurals=2; plural=(n != 1);\n"
- 
-+msgid "Folder Subscription"
-+msgstr "Ordner verwalten"
-+
- #: lib/Views/ShowMessage.php:295
- #, php-format
- msgid "%d Attachment"
-
--- 
-tg: (a6f8c8b..) t/dimp/H/GW/FoldersView (depends on: t/kronolith/H/GW/UseDayHourStartEndAlsoInFBView)
--- 
-TOPGIT patch commit log
-=======================
-
-commit c16643e792c3b185bc74bef7a600c06857b19406
-Author: Gunnar Wrobel <p at rdus.de>
-Date:   Mon Nov 9 23:16:11 2009 +0100
-
-    Fix tag name from view_imp to imp_view.
-
-commit 93403a869ff14d7868d4cc9c4687ea1270e3c225
-Author: Gunnar Wrobel <p at rdus.de>
-Date:   Mon Jun 22 08:39:51 2009 +0200
-
-    Typo
-
-commit ad147a4b42d61800400a2a779e884ee050358811
-Author: Gunnar Wrobel <p at rdus.de>
-Date:   Mon Jun 22 00:06:14 2009 +0200
-
-    Fixed menu entry name, added translation, fixed image.
-
-commit a1966161022108d9bf4831a8613b1db9a4e68c4d
-Author: Gunnar Wrobel <p at rdus.de>
-Date:   Fri Mar 13 11:06:45 2009 +0000
-
-    Include issue references in the patch description.
-
-commit de8c5e8cac0bfb29c9cf94989016487302da653f
-Author: Gunnar Wrobel <p at rdus.de>
-Date:   Fri Mar 13 11:04:54 2009 +0000
-
-    Exclude IMP specific functionality as requested by Sascha wilde in  kolab/issue3456 (There is no view in dimp that allows folder subscription).
-
-commit 9c9a343c04cf11f857bfeb4148f0ab9d9df7dce6
-Author: Gunnar Wrobel <p at rdus.de>
-Date:   Sun Mar 8 19:06:05 2009 +0000
-
-    Completed the hack.
-
-commit caa539aac138c4b77376ab9f4a4a86691709a96b
-Author: Gunnar Wrobel <p at rdus.de>
-Date:   Sun Mar 8 19:01:41 2009 +0000
-
-    Completed the hack.
diff --git a/kolab-webclient/dimp/patches/dimp-1.1.6/t_dimp_H_MS_CopyMessagesWithCtrl.diff b/kolab-webclient/dimp/patches/dimp-1.1.6/t_dimp_H_MS_CopyMessagesWithCtrl.diff
deleted file mode 100644
index ea6040c..0000000
--- a/kolab-webclient/dimp/patches/dimp-1.1.6/t_dimp_H_MS_CopyMessagesWithCtrl.diff
+++ /dev/null
@@ -1,629 +0,0 @@
-From: Gunnar Wrobel <p at rdus.de>
-Subject: [PATCH] t/dimp/H/MS/CopyMessagesWithCtrl
-
-Allow copying messages with Drag&Drop while holding Ctrl.
-
-https://www.intevation.de/roundup/kolab/issue4080
-
-STATUS: MERGED in HEAD but not in FRAMEWORK_3
-
-Signed-off-by: Gunnar Wrobel <p at rdus.de>
-
-diff -Naur a/DimpBase.js b/js/DimpBase.js
---- a/DimpBase.js	2010-04-14 22:21:28.000000000 +0200
-+++ b/js/DimpBase.js	2010-04-14 22:20:38.000000000 +0200
-@@ -1175,7 +1175,7 @@
-     },
- 
-     /* Drag/Drop handler. */
--    _folderDropHandler: function(drop, drag)
-+    _folderDropHandler: function(drop, drag, e)
-     {
-         var dropbase, sel, uids,
-             foldername = drop.readAttribute('mbox'),
-@@ -1198,10 +1198,14 @@
-                 uids = this.viewport.createSelection('domid', drag.id);
-             }
- 
--            // Don't allow drag/drop to the current folder.
--            if (uids.size() && this.folder != foldername) {
--                this.viewport.updateFlag(uids, 'deletedmsg', true);
--                DimpCore.doAction('MoveMessage', this.viewport.addRequestParams({ tofld: foldername }), DimpCore.toUIDArray(uids), this.bcache.get('deleteC') || this.bcache.set('deleteC', this._deleteCallback.bind(this)));
-+            if (uids.size()) {
-+                if (e.ctrlKey) {
-+                    DimpCore.doAction('CopyMessage', this.viewport.addRequestParams({ tofld: foldername }), DimpCore.toUIDArray(uids), this.bcache.get('pollFC') || this.bcache.set('pollFC', this._pollFoldersCallback.bind(this)));
-+                } else if (this.folder != foldername) {
-+                    // Don't allow drag/drop to the current folder.
-+                    this.viewport.updateFlag(uids, 'deletedmsg', true);
-+                    DimpCore.doAction('MoveMessage', this.viewport.addRequestParams({ tofld: foldername }), DimpCore.toUIDArray(uids), this.bcache.get('deleteC') || this.bcache.set('deleteC', this._deleteCallback.bind(this)));
-+                }
-             }
-         }
-     },
-@@ -2073,17 +2077,20 @@
- 
- DimpBase._folderDropConfig = {
-     hoverclass: 'dragdrop',
--    caption: function(drop, drag) {
--        var d = drag.readAttribute('l'),
-+    caption: function(drop, drag, e) {
-+        var m,
-+            d = drag.readAttribute('l'),
-             ftype = drop.readAttribute('ftype'),
--            l = drop.readAttribute('l'),
--            m = DIMP.text.moveto;
-+            l = drop.readAttribute('l');
-         if (drop == $('dropbase')) {
--            return m.replace(/%s/, d).replace(/%s/, DIMP.text.baselevel);
--        } else if (drag.hasClassName('folder')) {
--            return (ftype != 'special' && !this.isSubfolder(drag, drop)) ? m.replace(/%s/, d).replace(/%s/, l) : '';
-+            return DIMP.text.moveto.replace(/%s/, d).replace(/%s/, DIMP.text.baselevel);
-         } else {
--            return ftype != 'container' ? m.replace(/%s/, this._dragCaption()).replace(/%s/, l) : '';
-+            m = (e.ctrlKey) ? DIMP.text.copyto : DIMP.text.moveto;
-+            if (drag.hasClassName('folder')) {
-+                return (ftype != 'special' && !this.isSubfolder(drag, drop)) ? m.replace(/%s/, d).replace(/%s/, l) : '';
-+            } else {
-+                return ftype != 'container' ? m.replace(/%s/, this._dragCaption()).replace(/%s/, l) : '';
-+            }
-         }
-     }.bind(DimpBase),
-     onDrop: DimpBase._folderDropHandler.bind(DimpBase)
-diff -Naur a/dragdrop.js b/js/dragdrop.js
---- a/dragdrop.js	2010-04-14 22:21:28.000000000 +0200
-+++ b/js/dragdrop.js	2010-04-14 22:20:38.000000000 +0200
-@@ -1 +1,452 @@
--var DragDrop={Drags:{drags:$H(),register:function(a){if(!this.drags.size()){if(!this.div){this.div=new Element("DIV",{className:a.options.classname}).hide()}$(document.body).insert(this.div)}this.drags.set(a.element.readAttribute("id"),a)},unregister:function(a){if(this.drag==a.element){this.drag.deactivate()}this.drags.unset(a.element.readAttribute("id"));if(!this.drags.size()&&this.div){this.div.remove()}},get_drag:function(a){return this.drags.get(Object.isElement(a)?$(a).readAttribute("id"):a)},activate:function(a){if(this.drag){this.deactivate()}this.drag=a;this.mousemoveE=a._mouseMove.bindAsEventListener(a);this.mouseupE=a._mouseUp.bindAsEventListener(a);document.observe("mousemove",this.mousemoveE);document.observe("mouseup",this.mouseupE)},deactivate:function(){if(this.drag){this.drag=null;document.stopObserving("mousemove",this.mousemoveE);document.stopObserving("mouseup",this.mouseupE)}}},Drops:{drops:$H(),register:function(a){this.drops.set(a.element.readAttribut
 e("id"),a)},unregister:function(a){if(this.drop==a.element){this.drop=null}this.drops.unset(a.element.readAttribute("id"))},get_drop:function(a){return this.drops.get(Object.isElement(a)?$(a).readAttribute("id"):a)}},validDrop:function(a){var b=DragDrop.Drops.drop;return(b&&a&&a!=b.element&&(!b.options.accept.size()||b.options.accept.include(a.tagName)))}},Drag=Class.create({initialize:function(a){this.element=$(a);this.options=Object.extend({caption:"",classname:"drag",constraint:null,ghosting:false,scroll:null,snap:null,threshold:0,onDrag:null,onEnd:null,onStart:null},arguments[1]||{});this.mousedownE=this._mouseDown.bindAsEventListener(this);this.element.observe("mousedown",this.mousedownE);if(this.options.scroll){this.options.scroll=$(this.options.scroll)}DragDrop.Drags.register(this);if(Prototype.Browser.IE){this.element.observe("selectstart",Event.stop)}else{if(Prototype.Browser.Gecko){this.element.setStyle({MozUserSelect:"none"})}}},destroy:function(){this.element.sto
 pObserving("mousedown",this.mousedownE);DragDrop.Drags.unreg!
 ister(th
is)},_mouseDown:function(a){$(document.body).setStyle({cursor:"default"});DragDrop.Drags.activate(this);this.move=0;this.wasDragged=false;this.lastdrag=this.lastcaption=null;if(Object.isFunction(this.options.onStart)){this.options.onStart(this,a)}if(!Prototype.Browser.IE&&!Prototype.Browser.Gecko){a.stop()}},_mouseMove:function(f){var b,c,a,d;if(++this.move<=this.options.threshold){return}this.lastCoord=d=[f.pointerX(),f.pointerY()];if(this.options.ghosting){if(!this.ghost){b=this.element.offsetLeft;c=this.element.offsetTop;this.ghost=$(this.element.cloneNode(true)).writeAttribute("id",null).setOpacity(0.7).clonePosition(this.element,{setLeft:false,setTop:false}).setStyle({left:b+"px",position:"absolute",top:c+"px",zIndex:parseInt(this.element.getStyle("zIndex"))+1});this.element.insert({before:this.ghost});a=this.ghost.viewportOffset();this.ghostOffset=[a[0]-b,a[1]-c]}d[0]-=this.ghostOffset[0];d[1]-=this.ghostOffset[1];switch(this.options.constraint){case"horizontal":d[1]=th
 is.ghost.offsetTop;break;case"vertical":d[0]=this.ghost.offsetLeft;break}if(this.options.snap){d=this.options.snap(d[0],d[1],this.element)}if(this.options.offset){d[0]+=this.options.offset.x;d[1]+=this.options.offset.y}this._setContents(this.ghost,d[0],d[1])}this._onMoveDrag(d);if(Object.isFunction(this.options.onDrag)){this.options.onDrag(this,f)}this.wasDragged=true;if(this.options.scroll){this._onMoveScroll()}},_mouseUp:function(a){var b=DragDrop.Drops.drop;this._stopScrolling();if(this.ghost){this.ghost.remove();this.ghost=null}DragDrop.Drags.div.hide();if(DragDrop.validDrop(this.element)&&Object.isFunction(b.options.onDrop)){b.options.onDrop(b.element,this.element)}DragDrop.Drags.deactivate();if(Object.isFunction(this.options.onEnd)){this.options.onEnd(this,a)}},_onMoveDrag:function(g){var f,c,e,b,a,h=DragDrop.Drops.drop,i=DragDrop.Drags.div;if(h&&h.element!=this.lastdrag){if(DragDrop.validDrop(this.element)){b=h.options.caption;if(b){c=Object.isFunction(b)?b(h.element,
 this.element):b;if(c&&h.options.hoverclass){e=h.options.hove!
 rclass}a
=true}}else{a=true}this.lastdrag=h.element}else{if((!h&&this.lastdrag)||(this.move==(this.options.threshold+1))){a=true;this.lastdrag=null}}if(a){if(!c){f=this.options.caption;c=Object.isFunction(f)?f(this.element):f}this.lastcaption=c;i.update(c).writeAttribute({className:e||this.options.classname});if(c.empty()){i.hide()}}if(!this.lastcaption.empty()){this._setContents(i,g[0]+15,g[1]+(this.ghost?(this.ghost.getHeight()+5):5))}},_onMoveScroll:function(){this._stopScrolling();var e,d,b,a=this.options.scroll,c=a.getDimensions();if(a.scrollHeight==c.height){return}e=document.viewport.getScrollOffsets();d=a.viewportOffset(),b=[0,0];d[0]+=a.scrollLeft+e.left;d[2]=d[0]+c.width;if(this.lastCoord[0]>d[2]||this.lastCoord[0]<d[0]){return}d[1]+=a.scrollTop+e.top;d[3]=d[1]+c.height;if(this.lastCoord[1]<d[1]){b[1]=this.lastCoord[1]-d[1]}if(this.lastCoord[1]>d[3]){b[1]=this.lastCoord[1]-d[3]}if(b[0]||b[1]){this.lastScrolled=new Date();this.scrollInterval=setInterval(this._scroll.bind(this
 ,b[0]*15,b[1]*15),10)}},_stopScrolling:function(){if(this.scrollInterval){clearInterval(this.scrollInterval);this.scrollInterval=null}},_scroll:function(a,e){var c=new Date(),d=c-this.lastScrolled,b=this.options.scroll;this.lastScrolled=c;b.scrollTop+=e*d/1000},_setContents:function(c,a,e){var d=document.viewport.getDimensions(),b=c.getDimensions();if((a+b.width>d.width)||(e+b.height>d.height)){c.hide()}else{c.setStyle({left:a+"px",top:e+"px"}).show()}}}),Drop=Class.create({initialize:function(a){this.element=$(a);this.options=Object.extend({accept:[],caption:"",hoverclass:"",onDrop:null,onOut:null,onOver:null},arguments[1]||{});this.mouseoverE=this._mouseOver.bindAsEventListener(this);this.mouseoutE=this._mouseOut.bindAsEventListener(this);this.element.observe("mouseover",this.mouseoverE);this.element.observe("mouseout",this.mouseoutE);DragDrop.Drops.register(this)},destroy:function(){this.element.stopObserving("mouseover",this.mouseoverE);this.element.stopObserving("mouseo
 ut",this.mouseoutE);DragDrop.Drops.unregister(this)},_mouseO!
 ver:func
tion(a){if(DragDrop.Drags.drag){DragDrop.Drops.drop=this;if(Object.isFunction(this.options.onOver)){this.options.onOver(this.element,DragDrop.Drags.drag)}}},_mouseOut:function(a){if(Object.isFunction(this.options.onOut)){this.options.onOut(this.element,DragDrop.Drags.drag)}DragDrop.Drops.drop=null}});
-\ No newline at end of file
-+/**
-+ * dragdrop.js - A minimalist library to handle drag/drop actions.
-+ * Requires prototype.js 1.6.0.2+
-+ *
-+ * Adapted from SkyByte.js/SkyByteDD.js v1.0-beta, May 17 2007
-+ *   (c) 2007 Aleksandras Ilarionovas (Alex)
-+ *   http://www.skybyte.net/scripts/
-+ *
-+ * Scrolling and ghosting code adapted from script.aculo.us dragdrop.js v1.8.0
-+ *   (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
-+ *   (c) 2005-2007 Sammi Williams (http://www.oriontransfer.co.nz, sammi at oriontransfer.co.nz)
-+ *
-+ * The original scripts were freely distributable under the terms of an
-+ * MIT-style license.
-+ *
-+ * Usage:
-+ *   new Drag(element, {
-+ *       classname: '',           // Class name of the drag element
-+ *       caption: '',             // Either string or function to set caption
-+ *                                // on mouse move
-+ *       ghosting: false,         // Show ghost outline when dragging.
-+ *       offset: { x:0, y:0 },    // An offset to apply to ghosted elements.
-+ *       scroll: element,         // Scroll this element when above/below.
-+ *                                // Only working for vertical elements
-+ *       snap: null,              // If ghosting, snap allows to specify
-+ *                                // coords at which the ghosted image will
-+ *                                // "snap" into place.
-+ *       threshold: 0,            // Move threshold
-+ *       // For the following functions, d = drop element, e = event object
-+ *       onStart: function(d,e),  // A function to run on mousedown
-+ *       onDrag: function(d,e),   // A function to run on mousemove
-+ *       onEnd: function(d,e)     // A function to run on mouseup
-+ *   });
-+ *
-+ *   new Drop(element, {
-+ *       accept: [],           // Accept filter by tag name(s) or leave empty
-+ *                             // to accept all tags
-+ *       caption: '',          // Either string or function to set caption on
-+ *                             // mouse over
-+ *       hoverclass: '',       // Change the drag element to this class when
-+ *                             // hovering over an element.
-+ *       onDrop: function(drop,drag)  // Function fired when mouse button
-+ *                                    // released (a/k/a a drop event)
-+ *       onOver: function(drop,drag)  // Function fired when mouse over zone
-+ *       onOut: function(drop,drag)   // Function fired when mouse leaves the
-+ *                                    // zone
-+ *  });
-+ *
-+ * $Horde
-+ *
-+ * @author Michael Slusarz <slusarz at curecanti.org>
-+ */
-+
-+var DragDrop = {
-+    Drags: {
-+        drags: $H(),
-+
-+        register: function(obj)
-+        {
-+            if (!this.drags.size()) {
-+                if (!this.div) {
-+                    this.div = new Element('DIV', { className: obj.options.classname }).hide();
-+                }
-+                $(document.body).insert(this.div);
-+            }
-+
-+            this.drags.set(obj.element.readAttribute('id'), obj);
-+        },
-+
-+        unregister: function(obj)
-+        {
-+            if (this.drag == obj.element) {
-+                this.drag.deactivate();
-+            }
-+
-+            this.drags.unset(obj.element.readAttribute('id'));
-+
-+            if (!this.drags.size() && this.div) {
-+                this.div.remove();
-+            }
-+        },
-+
-+        get_drag: function(el)
-+        {
-+            return this.drags.get(Object.isElement(el) ? $(el).readAttribute('id') : el);
-+        },
-+
-+        activate: function(drag)
-+        {
-+            if (this.drag) {
-+                this.deactivate();
-+            }
-+            this.drag = drag;
-+            this.mousemoveE = drag._mouseMove.bindAsEventListener(drag);
-+            this.mouseupE = drag._mouseUp.bindAsEventListener(drag);
-+            document.observe('mousemove', this.mousemoveE);
-+            document.observe('mouseup', this.mouseupE);
-+        },
-+
-+        deactivate: function()
-+        {
-+            if (this.drag) {
-+                this.drag = null;
-+                document.stopObserving('mousemove', this.mousemoveE);
-+                document.stopObserving('mouseup', this.mouseupE);
-+            }
-+        }
-+    },
-+
-+    Drops: {
-+        drops: $H(),
-+
-+        register: function(obj)
-+        {
-+            this.drops.set(obj.element.readAttribute('id'), obj);
-+        },
-+
-+        unregister: function(obj)
-+        {
-+            if (this.drop == obj.element) {
-+                this.drop = null;
-+            }
-+
-+            this.drops.unset(obj.element.readAttribute('id'));
-+        },
-+
-+        get_drop: function(el)
-+        {
-+            return this.drops.get(Object.isElement(el) ? $(el).readAttribute('id') : el);
-+        }
-+    },
-+
-+    validDrop: function(el)
-+    {
-+        var d = DragDrop.Drops.drop;
-+        return (d &&
-+                el &&
-+                el != d.element &&
-+                (!d.options.accept.size() ||
-+                 d.options.accept.include(el.tagName)));
-+    }
-+},
-+
-+Drag = Class.create({
-+
-+    initialize: function(el) {
-+        this.element = $(el);
-+        this.options = Object.extend({
-+            caption: '',
-+            classname: 'drag',
-+            constraint: null,
-+            ghosting: false,
-+            scroll: null,
-+            snap: null,
-+            threshold: 0,
-+            onDrag: null,
-+            onEnd: null,
-+            onStart: null
-+        }, arguments[1] || {});
-+        this.mousedownE = this._mouseDown.bindAsEventListener(this);
-+        this.element.observe('mousedown', this.mousedownE);
-+        if (this.options.scroll) {
-+            this.options.scroll = $(this.options.scroll);
-+        }
-+        DragDrop.Drags.register(this);
-+
-+        // Disable text selection.
-+        // See: http://ajaxcookbook.org/disable-text-selection/
-+        // Stopping the event on mousedown works on all browsers, but avoid
-+        // that if possible because it will prevent any event handlers further
-+        // up the DOM tree from firing.
-+        if (Prototype.Browser.IE) {
-+            this.element.observe('selectstart', Event.stop);
-+        } else if (Prototype.Browser.Gecko) {
-+            this.element.setStyle({ MozUserSelect: 'none' });
-+        }
-+    },
-+
-+    destroy: function()
-+    {
-+        this.element.stopObserving('mousedown', this.mousedownE);
-+        DragDrop.Drags.unregister(this);
-+    },
-+
-+    _mouseDown: function(e)
-+    {
-+        $(document.body).setStyle({ cursor: 'default' });
-+        DragDrop.Drags.activate(this);
-+        this.move = 0;
-+        this.wasDragged = false;
-+        this.lastcaption = null;
-+
-+        if (Object.isFunction(this.options.onStart)) {
-+            this.options.onStart(this, e);
-+        }
-+
-+        if (!Prototype.Browser.IE && !Prototype.Browser.Gecko) {
-+            e.stop();
-+        }
-+    },
-+
-+    _mouseMove: function(e)
-+    {
-+        var oleft, otop, vo, xy;
-+
-+        if (++this.move <= this.options.threshold) {
-+            return;
-+        }
-+
-+        this.lastCoord = xy = [ e.pointerX(), e.pointerY() ];
-+
-+        if (this.options.ghosting) {
-+            if (!this.ghost) {
-+                oleft = this.element.offsetLeft;
-+                otop = this.element.offsetTop;
-+                this.ghost = $(this.element.cloneNode(true)).writeAttribute('id', null).setOpacity(0.7).clonePosition(this.element, { setLeft: false, setTop: false }).setStyle({ left: oleft + 'px', position: 'absolute', top: otop + 'px', zIndex: parseInt(this.element.getStyle('zIndex')) + 1 });
-+                this.element.insert({ before: this.ghost });
-+                vo = this.ghost.viewportOffset();
-+                this.ghostOffset = [ vo[0] - oleft, vo[1] - otop ];
-+            }
-+
-+            xy[0] -= this.ghostOffset[0];
-+            xy[1] -= this.ghostOffset[1];
-+
-+            switch (this.options.constraint) {
-+            case 'horizontal':
-+                xy[1] = this.ghost.offsetTop;
-+                break;
-+
-+            case 'vertical':
-+                xy[0] = this.ghost.offsetLeft;
-+                break;
-+            }
-+
-+            if (this.options.snap) {
-+                xy = this.options.snap(xy[0], xy[1], this.element);
-+            }
-+
-+            if (this.options.offset) {
-+                xy[0] += this.options.offset.x;
-+                xy[1] += this.options.offset.y;
-+            }
-+
-+            this._setContents(this.ghost, xy[0], xy[1]);
-+        }
-+
-+        this._onMoveDrag(xy, e);
-+
-+        if (Object.isFunction(this.options.onDrag)) {
-+            this.options.onDrag(this, e);
-+        }
-+
-+        this.wasDragged = true;
-+
-+        if (this.options.scroll) {
-+            this._onMoveScroll();
-+        }
-+    },
-+
-+    _mouseUp: function(e)
-+    {
-+        var d = DragDrop.Drops.drop;
-+
-+        this._stopScrolling();
-+
-+        if (this.ghost) {
-+            this.ghost.remove();
-+            this.ghost = null;
-+        }
-+        DragDrop.Drags.div.hide();
-+
-+        if (DragDrop.validDrop(this.element) &&
-+            Object.isFunction(d.options.onDrop)) {
-+            d.options.onDrop(d.element, this.element, e);
-+        }
-+
-+        DragDrop.Drags.deactivate();
-+
-+        if (Object.isFunction(this.options.onEnd)) {
-+            this.options.onEnd(this, e);
-+        }
-+    },
-+
-+    _onMoveDrag: function(xy, e)
-+    {
-+        var c_opt, caption, cname, d_cap,
-+            d = DragDrop.Drops.drop,
-+            div = DragDrop.Drags.div,
-+            d_update = true;
-+
-+        if (d && DragDrop.validDrop(this.element)) {
-+            d_cap = d.options.caption;
-+            if (d_cap) {
-+                caption = Object.isFunction(d_cap) ? d_cap(d.element, this.element, e) : d_cap;
-+                if (caption && d.options.hoverclass) {
-+                    cname = d.options.hoverclass;
-+                }
-+            } else {
-+                d_update = false;
-+            }
-+        }
-+
-+        if (d_update) {
-+            if (!caption) {
-+                c_opt = this.options.caption;
-+                caption = Object.isFunction(c_opt) ? c_opt(this.element) : c_opt;
-+            }
-+            if (caption != this.lastcaption) {
-+                this.lastcaption = caption;
-+                div.update(caption).writeAttribute({ className: cname || this.options.classname });
-+                if (caption.empty()) {
-+                    div.hide();
-+                }
-+            }
-+        }
-+
-+        if (!this.lastcaption.empty()) {
-+            this._setContents(div, xy[0] + 15, xy[1] + (this.ghost ? (this.ghost.getHeight() + 5) : 5));
-+        }
-+    },
-+
-+    _onMoveScroll: function()
-+    {
-+        this._stopScrolling();
-+
-+        var delta, p, speed,
-+            s = this.options.scroll,
-+            dim = s.getDimensions();
-+
-+        // No need to scroll if element is not current scrolling.
-+        if (s.scrollHeight == dim.height) {
-+            return;
-+        }
-+
-+        delta = document.viewport.getScrollOffsets();
-+        p = s.viewportOffset(),
-+        speed = [ 0, 0 ];
-+
-+        p[0] += s.scrollLeft + delta.left;
-+        p[2] = p[0] + dim.width;
-+
-+        // Only scroll if directly above/below element
-+        if (this.lastCoord[0] > p[2] ||
-+            this.lastCoord[0] < p[0]) {
-+            return;
-+        }
-+
-+        p[1] += s.scrollTop + delta.top;
-+        p[3] = p[1] + dim.height;
-+
-+        // Left scroll
-+        //if (this.lastCoord[0] < p[0]) {
-+        //    speed[0] = this.lastCoord[0] - p[0];
-+        //}
-+        // Top scroll
-+        if (this.lastCoord[1] < p[1]) {
-+            speed[1] = this.lastCoord[1] - p[1];
-+        }
-+        // Scroll right
-+        //if (this.lastCoord[0] > p[2]) {
-+        //    speed[0] = this.lastCoord[0] - p[2];
-+        //}
-+        // Scroll left
-+        if (this.lastCoord[1] > p[3]) {
-+            speed[1] = this.lastCoord[1] - p[3];
-+        }
-+
-+        if (speed[0] || speed[1]) {
-+            this.lastScrolled = new Date();
-+            this.scrollInterval = setInterval(this._scroll.bind(this, speed[0] * 15, speed[1] * 15), 10);
-+        }
-+    },
-+
-+    _stopScrolling: function()
-+    {
-+        if (this.scrollInterval) {
-+            clearInterval(this.scrollInterval);
-+            this.scrollInterval = null;
-+        }
-+    },
-+
-+    _scroll: function(x, y)
-+    {
-+        var current = new Date(),
-+            delta = current - this.lastScrolled,
-+            s = this.options.scroll;
-+        this.lastScrolled = current;
-+
-+        //s.scrollLeft += x * delta / 1000;
-+        s.scrollTop += y * delta / 1000;
-+    },
-+
-+    _setContents: function(elt, x, y)
-+    {
-+        var d_pos = document.viewport.getDimensions(),
-+            e_pos = elt.getDimensions();
-+
-+        if ((x + e_pos.width > d_pos.width) ||
-+            (y + e_pos.height > d_pos.height)) {
-+            elt.hide();
-+        } else {
-+            elt.setStyle({ left: x + 'px', top: y + 'px' }).show();
-+        }
-+    }
-+
-+}),
-+
-+Drop = Class.create({
-+
-+    initialize: function(el)
-+    {
-+        this.element = $(el);
-+        this.options = Object.extend({
-+            accept: [],
-+            caption: '',
-+            hoverclass: '',
-+            onDrop: null,
-+            onOut: null,
-+            onOver: null
-+        }, arguments[1] || {});
-+        this.mouseoverE = this._mouseOver.bindAsEventListener(this);
-+        this.mouseoutE = this._mouseOut.bindAsEventListener(this);
-+        this.element.observe('mouseover', this.mouseoverE);
-+        this.element.observe('mouseout', this.mouseoutE);
-+        DragDrop.Drops.register(this);
-+    },
-+
-+    destroy: function()
-+    {
-+        this.element.stopObserving('mouseover', this.mouseoverE);
-+        this.element.stopObserving('mouseout', this.mouseoutE);
-+        DragDrop.Drops.unregister(this);
-+    },
-+
-+    _mouseOver: function(e)
-+    {
-+        if (DragDrop.Drags.drag) {
-+            DragDrop.Drops.drop = this;
-+            if (Object.isFunction(this.options.onOver)) {
-+                this.options.onOver(this.element, DragDrop.Drags.drag);
-+            }
-+        }
-+    },
-+
-+    _mouseOut: function(e)
-+    {
-+        if (Object.isFunction(this.options.onOut)) {
-+            this.options.onOut(this.element, DragDrop.Drags.drag);
-+        }
-+        DragDrop.Drops.drop = null;
-+    }
-+});
-diff -Naur a/src/dragdrop.js b/js/src/dragdrop.js
---- a/src/dragdrop.js	2010-04-14 22:21:28.000000000 +0200
-+++ b/js/src/dragdrop.js	2010-04-14 22:20:38.000000000 +0200
-@@ -188,7 +188,7 @@
-         DragDrop.Drags.activate(this);
-         this.move = 0;
-         this.wasDragged = false;
--        this.lastdrag = this.lastcaption = null;
-+        this.lastcaption = null;
- 
-         if (Object.isFunction(this.options.onStart)) {
-             this.options.onStart(this, e);
-@@ -244,7 +244,7 @@
-             this._setContents(this.ghost, xy[0], xy[1]);
-         }
- 
--        this._onMoveDrag(xy);
-+        this._onMoveDrag(xy, e);
- 
-         if (Object.isFunction(this.options.onDrag)) {
-             this.options.onDrag(this, e);
-@@ -271,7 +271,7 @@
- 
-         if (DragDrop.validDrop(this.element) &&
-             Object.isFunction(d.options.onDrop)) {
--            d.options.onDrop(d.element, this.element);
-+            d.options.onDrop(d.element, this.element, e);
-         }
- 
-         DragDrop.Drags.deactivate();
-@@ -281,30 +281,23 @@
-         }
-     },
- 
--    _onMoveDrag: function(xy)
-+    _onMoveDrag: function(xy, e)
-     {
--        var c_opt, caption, cname, d_cap, d_update,
-+        var c_opt, caption, cname, d_cap,
-             d = DragDrop.Drops.drop,
--            div = DragDrop.Drags.div;
-+            div = DragDrop.Drags.div,
-+            d_update = true;
- 
--        if (d && d.element != this.lastdrag) {
--            if (DragDrop.validDrop(this.element)) {
--                d_cap = d.options.caption;
--                if (d_cap) {
--                    caption = Object.isFunction(d_cap) ? d_cap(d.element, this.element) : d_cap;
--                    if (caption && d.options.hoverclass) {
--                        cname = d.options.hoverclass;
--                    }
--                    d_update = true;
-+        if (d && DragDrop.validDrop(this.element)) {
-+            d_cap = d.options.caption;
-+            if (d_cap) {
-+                caption = Object.isFunction(d_cap) ? d_cap(d.element, this.element, e) : d_cap;
-+                if (caption && d.options.hoverclass) {
-+                    cname = d.options.hoverclass;
-                 }
-             } else {
--                d_update = true;
-+                d_update = false;
-             }
--            this.lastdrag = d.element;
--        } else if ((!d && this.lastdrag) ||
--                   (this.move == (this.options.threshold + 1))) {
--            d_update = true;
--            this.lastdrag = null;
-         }
- 
-         if (d_update) {
-@@ -312,10 +305,12 @@
-                 c_opt = this.options.caption;
-                 caption = Object.isFunction(c_opt) ? c_opt(this.element) : c_opt;
-             }
--            this.lastcaption = caption;
--            div.update(caption).writeAttribute({ className: cname || this.options.classname });
--            if (caption.empty()) {
--                div.hide();
-+            if (caption != this.lastcaption) {
-+                this.lastcaption = caption;
-+                div.update(caption).writeAttribute({ className: cname || this.options.classname });
-+                if (caption.empty()) {
-+                    div.hide();
-+                }
-             }
-         }
- 
-diff -Naur /kolab/var/kolab/www/client/dimp/lib/DIMP.php b/lib/DIMP.php
---- /kolab/var/kolab/www/client/dimp/lib/DIMP.php	2010-04-14 22:21:28.000000000 +0200
-+++ b/lib/DIMP.php	2010-04-14 22:20:38.000000000 +0200
-@@ -215,6 +215,7 @@
-             'showtext' => _("Show Quoted Text"),
-             'lines' => _("lines"),
-             'ok' => _("Ok"),
-+            'copyto' => _("Copy %s to %s"),
-             'moveto' => _("Move %s to %s"),
-             'baselevel' => _("base level of the folder tree"),
-             'cancel' => _("Cancel"),
diff --git a/kolab-webclient/dimp/patches/dimp-1.1.6/t_dimp_H_MS_FixBrokenFolderImages.diff b/kolab-webclient/dimp/patches/dimp-1.1.6/t_dimp_H_MS_FixBrokenFolderImages.diff
deleted file mode 100644
index de5686d..0000000
--- a/kolab-webclient/dimp/patches/dimp-1.1.6/t_dimp_H_MS_FixBrokenFolderImages.diff
+++ /dev/null
@@ -1,2235 +0,0 @@
-From: Gunnar Wrobel <p at rdus.de>
-Subject: [PATCH] t/dimp/H/MS/FixBrokenFolderImages
-
-Fixes broken custom folder images within DIMP.
-
-http://bugs.horde.org/ticket/7831
-
-https://www.intevation.de/roundup/kolab/issue3328
-
-STATUS: MERGED in HEAD but not in FRAMEWORK_3
-
-Signed-off-by: Gunnar Wrobel <p at rdus.de>
-
----
- /js/DimpBase.js     | 2149 ++++++++++++++++++++++++++++++++-
- js/src/DimpBase.js |    2 +-
- lib/DIMP.php       |    9 +-
- themes/screen.css  |    2 +-
- 4 files changed, 2157 insertions(+), 5 deletions(-)
-
-diff --git a/js/DimpBase.js b/js/DimpBase.js
-new file mode 100644
-index 0000000..96cd917
---- /dev/null
-+++ b/js/DimpBase.js
-@@ -0,0 +1,2146 @@
-+/**
-+ * DimpBase.js - Javascript used in the base DIMP page.
-+ *
-+ * $Horde: dimp/js/src/DimpBase.js,v 1.1.2.118 2009-05-20 18:27:51 slusarz Exp $
-+ *
-+ * Copyright 2005-2009 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.
-+ */
-+
-+var DimpBase = {
-+    // Vars used and defaulting to null/false:
-+    //   filtertoggle, fl_visible, folder, folderswitch, fspecial, isvisible,
-+    //   message_list_template, offset, pollpe, pp, searchobserve, uid,
-+    //   viewport
-+    bcache: $H(),
-+    delay_onload: (!Prototype.Browser.Gecko && !Prototype.Browser.Opera),
-+    lastrow: -1,
-+    mo_sidebar: $H(),
-+    pivotrow: -1,
-+    ppcache: $H(),
-+    ppfifo: [],
-+    showPreview: DIMP.conf.preview_pref,
-+
-+    sfiltersfolder: $H({ sf_all: 'all', sf_current: 'current' }),
-+    sfilters: $H({ sf_msgall: 'msgall', sf_from: 'from', sf_to: 'to', sf_subject: 'subject' }),
-+
-+    unseen_regex: new RegExp("(^|\\s)unseen(\\s|$)"),
-+
-+    // Message selection functions
-+
-+    // vs = (ViewPort_Selection) A ViewPort_Selection object.
-+    // opts = (object) Boolean options [delay, right]
-+    _select: function(vs, opts)
-+    {
-+        var d = vs.get('rownum');
-+        if (d.size() == 1) {
-+            this.lastrow = this.pivotrow = d.first();
-+        }
-+
-+        this.toggleButtons();
-+
-+        if ($('previewPane').visible()) {
-+            if (opts.right) {
-+                this.clearPreviewPane();
-+            } else {
-+                if (opts.delay) {
-+                    (this.bcache.get('initPP') || this.bcache.set('initPP', this.initPreviewPane.bind(this))).delay(opts.delay);
-+                } else {
-+                    this.initPreviewPane();
-+                }
-+            }
-+        }
-+    },
-+
-+    // vs = (ViewPort_Selection) A ViewPort_Selection object.
-+    // opts = (object) Boolean options [right]
-+    _deselect: function(vs, opts)
-+    {
-+        var sel = this.viewport.getSelected(),
-+            count = sel.size();
-+        if (!count) {
-+            this.lastrow = this.pivotrow = -1;
-+        }
-+
-+        this.toggleButtons();
-+        if (opts.right || !count) {
-+            this.clearPreviewPane();
-+        } else if ((count == 1) && $('previewPane').visible()) {
-+            this._loadPreview(sel.get('dataob').first());
-+        }
-+    },
-+
-+    // id = (string) DOM ID
-+    // opts = (Object) Boolean options [ctrl, right, shift]
-+    msgSelect: function(id, opts)
-+    {
-+        var bounds,
-+            row = this.viewport.createSelection('domid', id),
-+            rownum = row.get('rownum').first(),
-+            sel = this.isSelected('domid', id),
-+            selcount = this.selectedCount();
-+
-+        this.lastrow = rownum;
-+
-+        // Some browsers need to stop the mousedown event before it propogates
-+        // down to the browser level in order to prevent text selection on
-+        // drag/drop actions.  Clicking on a message should always lose focus
-+        // from the search input, because the user may immediately start
-+        // keyboard navigation after that. Thus, we need to ensure that a
-+        // message click loses focus on the search input.
-+        $('msgList_filter').blur();
-+
-+        if (opts.shift) {
-+            if (selcount) {
-+                if (!sel || selcount != 1) {
-+                    bounds = [ rownum, this.pivotrow ];
-+                    this.viewport.select($A($R(bounds.min(), bounds.max())), { range: true });
-+                }
-+                return;
-+            }
-+        } else if (opts.ctrl) {
-+            this.pivotrow = rownum;
-+            if (sel) {
-+                this.viewport.deselect(row, { right: opts.right });
-+                return;
-+            } else if (opts.right || selcount) {
-+                this.viewport.select(row, { add: true, right: opts.right });
-+                return;
-+            }
-+        }
-+
-+        this.viewport.select(row, { right: opts.right });
-+    },
-+
-+    selectAll: function()
-+    {
-+        this.viewport.select($A($R(1, this.viewport.getMetaData('total_rows'))), { range: true });
-+    },
-+
-+    isSelected: function(format, data)
-+    {
-+        return this.viewport.getSelected().contains(format, data);
-+    },
-+
-+    selectedCount: function()
-+    {
-+        return (this.viewport) ? this.viewport.getSelected().size() : 0;
-+    },
-+
-+    resetSelected: function()
-+    {
-+        if (this.viewport) {
-+            this.viewport.deselect(this.viewport.getSelected(), { clearall: true });
-+        }
-+        this.toggleButtons();
-+        this.clearPreviewPane();
-+    },
-+
-+    // absolute = Is num an absolute row number - from 1 -> page_size (true) -
-+    //            or a relative change from the current selected value (false)
-+    //            If no current selected value, the first message in the
-+    //            current viewport is selected.
-+    moveSelected: function(num, absolute)
-+    {
-+        var curr, curr_row, row, row_data, sel;
-+
-+        if (absolute) {
-+            if (!this.viewport.getMetaData('total_rows')) {
-+                return;
-+            }
-+            curr = num;
-+        } else {
-+            if (num == 0) {
-+                return;
-+            }
-+
-+            sel = this.viewport.getSelected();
-+            switch (sel.size()) {
-+            case 0:
-+                curr = this.viewport.currentOffset();
-+                curr += (num > 0) ? 1 : this.viewport.getPageSize('current');
-+                break;
-+
-+            case 1:
-+                curr_row = sel.get('dataob').first();
-+                curr = curr_row.rownum + num;
-+                break;
-+
-+            default:
-+                sel = sel.get('rownum');
-+                curr = (num > 0 ? sel.max() : sel.min()) + num;
-+                break;
-+            }
-+            curr = (num > 0) ? Math.min(curr, this.viewport.getMetaData('total_rows')) : Math.max(curr, 1);
-+        }
-+
-+        row = this.viewport.createSelection('rownum', curr);
-+        if (row.size()) {
-+            row_data = row.get('dataob').first();
-+            if (!curr_row || row_data.imapuid != curr_row.imapuid) {
-+                this.viewport.scrollTo(row_data.rownum);
-+                this.viewport.select(row, { delay: 0.3 });
-+            }
-+        } else {
-+            this.offset = curr;
-+            this.viewport.requestContentRefresh(curr - 1);
-+        }
-+    },
-+    // End message selection functions
-+
-+    go: function(loc, data)
-+    {
-+        var app, f, separator;
-+
-+        if (loc.startsWith('compose:')) {
-+            return;
-+        }
-+
-+        if (loc.startsWith('msg:')) {
-+            separator = loc.indexOf(':', 4);
-+            f = loc.substring(4, separator);
-+            this.uid = loc.substring(separator + 1);
-+            loc = 'folder:' + f;
-+            // Now fall through to the 'folder:' check below.
-+        }
-+
-+        if (loc.startsWith('folder:')) {
-+            f = loc.substring(7);
-+            if (this.folder != f || !$('dimpmain_folder').visible()) {
-+                this.highlightSidebar(this.getFolderId(f));
-+                if (!$('dimpmain_folder').visible()) {
-+                    $('dimpmain_portal').hide();
-+                    $('dimpmain_folder').show();
-+                }
-+                // This catches the refresh case - no need to re-add to history
-+                if (!Object.isUndefined(this.folder)) {
-+                    this._addHistory(loc);
-+                }
-+            }
-+            this.loadFolder(f);
-+            return;
-+        }
-+
-+        this.folder = null;
-+        $('dimpmain_folder').hide();
-+        $('dimpmain_portal').update(DIMP.text.loading).show();
-+
-+        if (loc.startsWith('app:')) {
-+            app = loc.substr(4);
-+            if (app == 'imp' || app == 'dimp') {
-+                this.go('folder:INBOX');
-+                return;
-+            }
-+            this.highlightSidebar('app' + app);
-+            this._addHistory(loc, data);
-+            if (data) {
-+                this.iframeContent(loc, data);
-+            } else if (DIMP.conf.app_urls[app]) {
-+                this.iframeContent(loc, DIMP.conf.app_urls[app]);
-+            }
-+            return;
-+        }
-+
-+        switch (loc) {
-+        case 'portal':
-+            this.highlightSidebar('appportal');
-+            this._addHistory(loc);
-+            DimpCore.setTitle(DIMP.text.portal);
-+            DimpCore.doAction('ShowPortal', {}, [], this.bcache.get('portalC') || this.bcache.set('portalC', this._portalCallback.bind(this)));
-+            break;
-+
-+        case 'options':
-+            this.highlightSidebar('appoptions');
-+            this._addHistory(loc);
-+            DimpCore.setTitle(DIMP.text.prefs);
-+            this.iframeContent(loc, DIMP.conf.prefs_url);
-+            break;
-+        }
-+    },
-+
-+    _addHistory: function(loc, data)
-+    {
-+        if (Horde.dhtmlHistory.getCurrentLocation() != loc) {
-+            Horde.dhtmlHistory.add(loc, data);
-+        }
-+    },
-+
-+    highlightSidebar: function(id)
-+    {
-+        // Folder bar may not be fully loaded yet.
-+        if ($('foldersLoading').visible()) {
-+            this.highlightSidebar.bind(this, id).defer();
-+            return;
-+        }
-+
-+        $('sidebarPanel').select('.on').invoke('removeClassName', 'on');
-+
-+        var elt = $(id);
-+        if (!elt) {
-+            return;
-+        }
-+        if (!elt.match('LI')) {
-+            elt = elt.up();
-+            if (!elt) {
-+                return;
-+            }
-+        }
-+        elt.addClassName('on');
-+
-+        // Make sure all subfolders are expanded
-+        elt.ancestors().find(function(n) {
-+            if (n.hasClassName('subfolders')) {
-+                this._toggleSubFolder(n.id.substring(3), 'exp');
-+            } else {
-+                return (n.id == 'foldersSidebar');
-+            }
-+        }, this);
-+    },
-+
-+    iframeContent: function(name, loc)
-+    {
-+        if (name === null) {
-+            name = loc;
-+        }
-+
-+        var container = $('dimpmain_portal'), iframe;
-+        if (!container) {
-+            DimpCore.showNotifications([ { type: 'horde.error', message: 'Bad portal!' } ]);
-+            return;
-+        }
-+
-+        iframe = new Element('IFRAME', { id: 'iframe' + name, className: 'iframe', frameBorder: 0, src: loc });
-+        this._resizeIE6Iframe(iframe);
-+
-+        // Hide menu in prefs pages.
-+        if (name == 'options') {
-+            iframe.observe('load', function() { $('iframeoptions').contentWindow.document.getElementById('menu').style.display = 'none'; });
-+        }
-+
-+        container.insert(iframe);
-+    },
-+
-+    // r = ViewPort row data
-+    msgWindow: function(r)
-+    {
-+        this.updateUnseenUID(r, 0);
-+        var url = DIMP.conf.message_url;
-+        url += (url.include('?') ? '&' : '?') +
-+               $H({ folder: r.view,
-+                    uid: r.imapuid }).toQueryString();
-+        DimpCore.popupWindow(url, 'msgview' + r.view + r.imapuid);
-+    },
-+
-+    composeMailbox: function(type)
-+    {
-+        var sel = this.viewport.getSelected();
-+        if (!sel.size()) {
-+            return;
-+        }
-+        sel.get('dataob').each(function(s) {
-+            DimpCore.compose(type, { folder: s.view, uid: s.imapuid });
-+        });
-+    },
-+
-+    loadFolder: function(f, background)
-+    {
-+        if (!this.viewport) {
-+            this._createViewPort();
-+        }
-+
-+        if (!background) {
-+            this.resetSelected();
-+
-+            if (this.folder == f) {
-+                this.searchfilterClear(false);
-+                return;
-+            }
-+
-+            this.searchfilterClear(true);
-+            $('folderName').update(DIMP.text.loading);
-+            $('msgHeader').update();
-+            this.folderswitch = true;
-+            this.folder = f;
-+        }
-+
-+        this.viewport.loadView(f, { folder: f }, this.uid ? { imapuid: DimpCore.toUIDString(this.uid, f) } : null, background);
-+    },
-+
-+    _createViewPort: function()
-+    {
-+        var mf = $('msgList_filter'),
-+            // No need to cache - this function only called once.
-+            settitle = this.setMessageListTitle.bind(this);
-+
-+        this.viewport = new ViewPort({
-+            content_container: 'msgList',
-+            empty_container: 'msgList_empty',
-+            error_container: 'msgList_error',
-+            fetch_action: 'ListMessages',
-+            template: this.message_list_template,
-+            buffer_pages: DIMP.conf.buffer_pages,
-+            limit_factor: DIMP.conf.limit_factor,
-+            viewport_wait: DIMP.conf.viewport_wait,
-+            show_split_pane: this.showPreview,
-+            split_pane: 'previewPane',
-+            splitbar: 'splitBar',
-+            content_class: 'msglist',
-+            row_class: 'msgRow',
-+            selected_class: 'selectedRow',
-+            ajaxRequest: DimpCore.doAction.bind(DimpCore),
-+            norows: true,
-+            onScrollIdle: settitle,
-+            onSlide: settitle,
-+            onViewChange: function() {
-+                DimpCore.addGC(this.viewport.visibleRows());
-+            }.bind(this),
-+            onContent: function(rows) {
-+                var mf, search,
-+                    thread = ((this.viewport.getMetaData('sortby') == DIMP.conf.sortthread) && this.viewport.getMetaData('thread'));
-+                if (this.viewport.isFiltering()) {
-+                    search = this.sfilters.get(this._getSearchfilterField()).capitalize();
-+                    mf = new RegExp("(" + $F('msgList_filter') + ")", "i");
-+                }
-+                rows.get('dataob').each(function(row) {
-+                    var elt, tmp, u,
-+                        r = $(row.domid);
-+                    // Add thread graphics
-+                    if (thread && thread[row.imapuid]) {
-+                        elt = r.down('.msgSubject');
-+                        tmp = elt.cloneNode(false);
-+                        u = thread[row.imapuid];
-+                        $R(0, u.length, true).each(function(i) {
-+                            tmp.insert($($('thread_img_' + u.charAt(i)).cloneNode(false)).writeAttribute('id', ''));
-+                        });
-+                        elt.replace(tmp.insert(elt.getText().escapeHTML()));
-+                    }
-+                    // Add attachment graphics
-+                    if (row.atc) {
-+                        r.down('.msgSize').insert({ top: $($('atc_img_' + row.atc).cloneNode(false)).writeAttribute('id', '') });
-+                    }
-+
-+                    // Add context menu.
-+                    DimpCore.addMouseEvents({ id: row.domid, type: row.menutype });
-+
-+                    // Highlight search terms
-+                    if (search == 'From' || search == 'Subject') {
-+                        elt = r.down('.msg' + search);
-+                        elt.update(elt.getText().escapeHTML().gsub(mf, '<span class="searchMatch">#{1}</span>'));
-+                    }
-+                }, this);
-+                this.setMessageListTitle();
-+            }.bind(this),
-+            onComplete: function() {
-+                var row, ssc,
-+                    l = this.viewport.getMetaData('label');
-+
-+                if (this.uid) {
-+                    row = this.viewport.getViewportSelection().search({ imapuid: { equal: [ this.uid ] }, view: { equal: [ this.folder ] } });
-+                    if (row.size()) {
-+                        this.viewport.scrollTo(row.get('rownum').first());
-+                        this.viewport.select(row);
-+                    }
-+                } else if (this.offset) {
-+                    this.viewport.select(this.viewport.createSelection('rownum', this.offset));
-+                }
-+                this.offset = this.uid = null;
-+
-+                // 'label' will not be set if there has been an error
-+                // retrieving data from the server.
-+                l = this.viewport.getMetaData('label');
-+                if (l) {
-+                    $('folderName').update(l);
-+                }
-+
-+                if (this.folderswitch) {
-+                    this.folderswitch = false;
-+                    if (this.folder == DIMP.conf.spam_folder) {
-+                        if (!DIMP.conf.spam_spamfolder &&
-+                            DimpCore.buttons.indexOf('button_spam') != -1) {
-+                            [ $('button_spam').up(), $('ctx_message_spam') ].invoke('hide');
-+                        }
-+                        if (DimpCore.buttons.indexOf('button_ham') != -1) {
-+                            [ $('button_ham').up(), $('ctx_message_ham') ].invoke('show');
-+                        }
-+                    } else {
-+                        if (DimpCore.buttons.indexOf('button_spam') != -1) {
-+                            [ $('button_spam').up(), $('ctx_message_spam') ].invoke('show');
-+                        }
-+                        if (DimpCore.buttons.indexOf('button_ham') != -1) {
-+                            if (DIMP.conf.ham_spamfolder) {
-+                                [ $('button_ham').up(), $('ctx_message_ham') ].invoke('hide');
-+                            } else {
-+                                [ $('button_ham').up(), $('ctx_message_ham') ].invoke('show');
-+                            }
-+                        }
-+                    }
-+                } else if (this.filtertoggle) {
-+                    if (this.filtertoggle == 1 &&
-+                        this.viewport.getMetaData('sortby') == DIMP.conf.sortthread) {
-+                        ssc = DIMP.conf.sortdate;
-+                    }
-+                    this.filtertoggle = 0;
-+                }
-+
-+                this.setSortColumns(ssc);
-+
-+                if (this.viewport.isFiltering()) {
-+                    this.resetSelected();
-+                    this.updateTitle();
-+                } else {
-+                    this.setFolderLabel(this.folder, this.viewport.getMetaData('unseen'));
-+                }
-+            }.bind(this),
-+            onFetch: this.msgListLoading.bind(this, true),
-+            onEndFetch: this.msgListLoading.bind(this, false),
-+            onWait: function() {
-+                if ($('dimpmain_folder').visible()) {
-+                    DimpCore.showNotifications([ { type: 'horde.warning', message: DIMP.text.listmsg_wait } ]);
-+                }
-+            },
-+            onFail: function() {
-+                if ($('dimpmain_folder').visible()) {
-+                    DimpCore.showNotifications([ { type: 'horde.error', message: DIMP.text.listmsg_timeout } ]);
-+                }
-+                this.msgListLoading(false);
-+            }.bind(this),
-+            onFirstContent: function() {
-+                this.clearPreviewPane();
-+                $('msgList').observe('dblclick', this._handleMsgListDblclick.bindAsEventListener(this));
-+            }.bind(this),
-+            onClearRows: function(r) {
-+                r.each(function(row) {
-+                    var c = $(row).down('div.msCheck');
-+                    if (c) {
-+                        DimpCore.addGC(c);
-+                    }
-+                    if (row.id) {
-+                        DimpCore.removeMouseEvents(row);
-+                    }
-+                });
-+            },
-+            onBeforeResize: function() {
-+                var sel = this.viewport.getSelected();
-+                this.isvisible = (sel.size() == 1) && (this.viewport.isVisible(sel.get('rownum').first()) == 0);
-+            }.bind(this),
-+            onAfterResize: function() {
-+                if (this.isvisible) {
-+                    this.viewport.scrollTo(this.viewport.getSelected().get('rownum').first());
-+                }
-+            }.bind(this),
-+            selectCallback: this._select.bind(this),
-+            deselectCallback: this._deselect.bind(this)
-+        });
-+
-+        // If starting in no preview mode, need to set the no preview class
-+        if (!this.showPreview) {
-+            $('msgList').addClassName('msglistNoPreview');
-+        }
-+
-+        // Set up viewport filter events.
-+        this.viewport.addFilter('ListMessages', this._addSearchfilterParams.bind(this));
-+        mf.observe('keyup', this._searchfilterOnKeyup.bind(this));
-+        mf.observe('focus', this._searchfilterOnFocus.bind(this));
-+        mf.observe('blur', this._searchfilterOnBlur.bind(this));
-+        mf.addClassName('msgFilterDefault');
-+    },
-+
-+    _addMouseEvents: function(parentfunc, p)
-+    {
-+        var elt;
-+
-+        switch (p.type) {
-+        case 'draft':
-+        case 'message':
-+            new Drag(p.id, this._msgDragConfig);
-+            elt = $(p.id).down('div.msCheck');
-+            if (elt.visible()) {
-+                elt.observe('mousedown', this.bcache.get('handleMLC') || this.bcache.set('handleMLC', this._handleMsgListCheckbox.bindAsEventListener(this)));
-+                elt.observe('contextmenu', Event.stop);
-+            }
-+            break;
-+
-+        case 'container':
-+        case 'folder':
-+            new Drag(p.id, this._folderDragConfig);
-+            break;
-+
-+        case 'special':
-+            // For purposes of the contextmenu, treat special folders
-+            // like regular folders.
-+            p.type = 'folder';
-+            break;
-+        }
-+        p.onShow = this.bcache.get('onMS') || this.bcache.set('onMS', this._onMenuShow.bind(this));
-+        parentfunc(p);
-+    },
-+
-+    _removeMouseEvents: function(parentfunc, elt)
-+    {
-+        var d, id = $(elt).readAttribute('id');
-+        if (id && (d = DragDrop.Drags.get_drag(id))) {
-+            d.destroy();
-+        }
-+        parentfunc(elt);
-+    },
-+
-+    _onMenuShow: function(ctx)
-+    {
-+        var elts, folder, ob, sel;
-+
-+        switch (ctx.ctx) {
-+        case 'ctx_folder':
-+            elts = $('ctx_folder_create', 'ctx_folder_rename', 'ctx_folder_delete');
-+            folder = DimpCore.DMenu.element();
-+            if (folder.readAttribute('mbox') == 'INBOX') {
-+                elts.invoke('hide');
-+            } else if (DIMP.conf.fixed_folders.indexOf(folder.readAttribute('mbox')) != -1) {
-+                elts.shift();
-+                elts.invoke('hide');
-+            } else {
-+                elts.invoke('show');
-+            }
-+
-+            if (folder.hasAttribute('u')) {
-+                $('ctx_folder_poll').hide();
-+                $('ctx_folder_nopoll').show();
-+            } else {
-+                $('ctx_folder_poll').show();
-+                $('ctx_folder_nopoll').hide();
-+            }
-+            break;
-+
-+        case 'ctx_message':
-+            [ $('ctx_message_reply_list') ].invoke( this.viewport.createSelection('domid', ctx.id).get('dataob').first().listmsg ? 'show' : 'hide');
-+            break;
-+
-+        case 'ctx_reply':
-+            sel = this.viewport.getSelected();
-+            if (sel.size() == 1) {
-+                ob = sel.get('dataob').first();
-+            }
-+            [ $('ctx_reply_reply_list') ].invoke(ob && ob.listmsg ? 'show' : 'hide');
-+            break;
-+
-+        case 'ctx_otheractions':
-+            $('oa_seen', 'oa_unseen', 'oa_flagged', 'oa_clear', 'oa_sep1', 'oa_blacklist', 'oa_whitelist', 'oa_sep2', 'oa_undelete').compact().invoke(this.viewport.getSelected().size() ? 'show' : 'hide');
-+            break;
-+        }
-+        return true;
-+    },
-+
-+    _onResize: function()
-+    {
-+        if (this.viewport) {
-+            this.viewport.onResize();
-+        }
-+        this._resizeIE6();
-+    },
-+
-+    _handleMsgListDblclick: function(e)
-+    {
-+        var elt = this._getMsgRow(e);
-+        if (!elt) {
-+            return;
-+        }
-+        var row = this.viewport.createSelection('domid', elt.id).get('dataob').first();
-+        row.draft ? DimpCore.compose('resume', { folder: row.view, uid: row.imapuid }) : this.msgWindow(row);
-+        e.stop();
-+    },
-+
-+    _handleMsgListCheckbox: function(e)
-+    {
-+        var elt = this._getMsgRow(e);
-+        if (!elt) {
-+            return;
-+        }
-+        this.msgSelect(elt.readAttribute('id'), { ctrl: true, right: true });
-+        e.stop();
-+    },
-+
-+    _getMsgRow: function(e)
-+    {
-+        e = e.element();
-+        if (e && !e.hasClassName('msgRow')) {
-+            e = e.up('.msgRow');
-+        }
-+        return e;
-+    },
-+
-+    updateTitle: function()
-+    {
-+        var elt, label, unseen;
-+        if (this.viewport.isFiltering()) {
-+            label = DIMP.text.search + ' :: ' + this.viewport.getMetaData('total_rows') + ' ' + DIMP.text.resfound;
-+        } else {
-+            elt = $(this.getFolderId(this.folder));
-+            if (elt) {
-+                unseen = elt.readAttribute('u');
-+                label = elt.readAttribute('l');
-+                if (unseen > 0) {
-+                    label += ' (' + unseen + ')';
-+                }
-+            } else {
-+                label = this.viewport.getMetaData('label');
-+            }
-+        }
-+        DimpCore.setTitle(label);
-+    },
-+
-+    sort: function(e)
-+    {
-+        // Don't change sort if we are past the sortlimit
-+        if (this.viewport.getMetaData('sortlimit')) {
-+            return;
-+        }
-+
-+        var s, sortby,
-+            elt = e.element();
-+        if (!elt.hasAttribute('sortby')) {
-+            elt = elt.up('[sortby]');
-+            if (!elt) {
-+                return;
-+            }
-+        }
-+        sortby = parseInt(elt.readAttribute('sortby'), 10);
-+
-+        if (sortby == this.viewport.getMetaData('sortby')) {
-+            s = { sortdir: (this.viewport.getMetaData('sortdir') ? 0 : 1) };
-+            this.viewport.setMetaData({ sortdir: s.sortdir });
-+        } else {
-+            s = { sortby: sortby };
-+            this.viewport.setMetaData({ sortby: s.sortby });
-+        }
-+        this.setSortColumns(sortby);
-+        this.viewport.reload(s);
-+    },
-+
-+    setSortColumns: function(sortby)
-+    {
-+        var tmp,
-+            m = $('msglistHeader');
-+
-+        if (Object.isUndefined(sortby)) {
-+            sortby = this.viewport.getMetaData('sortby');
-+        }
-+
-+        tmp = m.down('small[sortby=' + sortby + ']');
-+        if (tmp && tmp.up().visible()) {
-+           tmp.up(1).childElements().invoke('toggle');
-+        }
-+
-+        tmp = m.down('div.msgFrom a');
-+        if ((this.viewport.isFiltering() && this.fspecial) ||
-+            this.viewport.getMetaData('special')) {
-+            tmp.hide().next().show();
-+        } else {
-+            tmp.show().next().hide();
-+        }
-+
-+        tmp = m.down('div.msgSubject a');
-+        if (this.viewport.isFiltering() ||
-+            this.viewport.getMetaData('nothread') ||
-+            this.viewport.getMetaData('sortlimit')) {
-+            tmp.show().next().hide();
-+            tmp.down().hide();
-+        } else {
-+            tmp.down().show();
-+        }
-+
-+        m.childElements().invoke('removeClassName', 'sortup').invoke('removeClassName', 'sortdown');
-+        m.down('div a[sortby=' + sortby + ']').up().addClassName(this.viewport.getMetaData('sortdir') ? 'sortup' : 'sortdown');
-+    },
-+
-+    // Preview pane functions
-+    togglePreviewPane: function()
-+    {
-+        this.showPreview = !this.showPreview;
-+        $('previewtoggle').setText(this.showPreview ? DIMP.text.hide_preview : DIMP.text.show_preview);
-+        [ $('msgList') ].invoke(this.showPreview ? 'removeClassName' : 'addClassName', 'msglistNoPreview');
-+        new Ajax.Request(DimpCore.addSID(DIMP.conf.URI_PREFS), { parameters: { app: 'dimp', pref: 'show_preview', value: this.showPreview ? 1 : 0 } });
-+        this.viewport.showSplitPane(this.showPreview);
-+        if (this.showPreview) {
-+            this.initPreviewPane();
-+        }
-+        this.updateTitle();
-+    },
-+
-+    _loadPreview: function(data)
-+    {
-+        var pp = $('previewPane'), pp_offset;
-+        if (!pp.visible()) {
-+            return;
-+        }
-+        if (this.pp &&
-+            this.pp == data) {
-+            return;
-+        }
-+        this.pp = data;
-+
-+        if (this.ppfifo.indexOf(data.vp_id) != -1) {
-+            return this._loadPreviewCallback(this.ppcache.get(data.vp_id));
-+        }
-+
-+        pp_offset = pp.positionedOffset();
-+        $('msgLoading').setStyle({ position: 'absolute', top: (pp_offset.top + 10) + 'px', left: (pp_offset.left + 10) + 'px' }).show();
-+
-+        DimpCore.doAction('ShowPreview', {}, DimpCore.toUIDArray(this.viewport.createSelection('dataob', data)), this.bcache.get('loadPC') || this.bcache.set('loadPC', this._loadPreviewCallback.bind(this)));
-+    },
-+
-+    _loadPreviewCallback: function(resp)
-+    {
-+        var row, search, tmp, tmp2,
-+            pm = $('previewMsg'),
-+            r = resp.response;
-+
-+        if (!r.error) {
-+            search = this.viewport.getViewportSelection(r.view).search({ vp_id: { equal: [ r.uid ] } });
-+            if (search.size()) {
-+                row = search.get('dataob').first();
-+                this.updateUnseenUID(row, 0);
-+            }
-+        }
-+
-+        if (this.pp &&
-+            this.pp.vp_id != r.uid) {
-+            return;
-+        }
-+
-+        if (r.error || this.viewport.getSelected().size() != 1) {
-+            if (r.error) {
-+                DimpCore.showNotifications([ { type: r.errortype, message: r.error } ]);
-+            }
-+            this.clearPreviewPane();
-+            return;
-+        }
-+
-+        // Store in cache.
-+        this._expirePPCache([ r.uid ]);
-+        this.ppcache.set(r.uid, resp);
-+        this.ppfifo.push(r.uid);
-+
-+        DimpCore.removeAddressLinks(pm);
-+
-+        DIMP.conf.msg_index = r.index;
-+        DIMP.conf.msg_folder = r.folder;
-+        DIMP.conf.msg_source_link = r.source_link;
-+
-+        // Add subject/priority
-+        tmp = pm.select('.subject');
-+        tmp.invoke('update', r.subject);
-+        switch (r.priority) {
-+        case 'high':
-+        case 'low':
-+            tmp.invoke('insert', { top: $($(r.priority + '_priority_img').cloneNode(false)).writeAttribute('id', false) });
-+            break;
-+        }
-+
-+        // Add from/date
-+        pm.select('.from').invoke('update', r.from);
-+        $('msgHeadersColl').select('.date').invoke('update', r.minidate);
-+        $('msgHeaderDate').select('.date').invoke('update', r.fulldate);
-+
-+        // Add to/cc
-+        [ 'to', 'cc' ].each(function(a) {
-+            if (r[a]) {
-+                pm.select('.' + a).invoke('update', r[a]);
-+            }
-+            [ $('msgHeader' + a.capitalize()) ].invoke(r[a] ? 'show' : 'hide');
-+        });
-+
-+        // Add attachment information
-+        $('msgHeadersColl').select('.attachmentImage').invoke(r.atc_label ? 'show' : 'hide');
-+        if (r.atc_label) {
-+            tmp = $('msgAtc').show().down('.label');
-+            tmp2 = $('partlist');
-+            tmp2.hide().previous().update(r.atc_label + ' ' + r.atc_download);
-+            if (r.atc_list) {
-+                $('partlist_col').show();
-+                $('partlist_exp').hide();
-+                tmp.down().hide().next().show();
-+                tmp2.update(r.atc_list);
-+            } else {
-+                tmp.down().show().next().hide();
-+            }
-+        } else {
-+            $('msgAtc').hide();
-+        }
-+
-+        $('msgBody').down().update(r.msgtext);
-+        $('msgLoading', 'previewInfo').invoke('hide');
-+        $('previewPane').scrollTop = 0;
-+        pm.show();
-+
-+        if (r.js) {
-+            eval(r.js.join(';'));
-+        }
-+        DimpCore.buildAddressLinks(pm);
-+        this._addHistory('msg:' + row.view + ':' + row.imapuid);
-+    },
-+
-+    initPreviewPane: function()
-+    {
-+        var sel = this.viewport.getSelected();
-+        if (sel.size() != 1) {
-+            this.clearPreviewPane();
-+        } else {
-+            this._loadPreview(sel.get('dataob').first());
-+        }
-+    },
-+
-+    clearPreviewPane: function()
-+    {
-+        $('msgLoading', 'previewMsg').invoke('hide');
-+        $('previewInfo').show();
-+        this.pp = null;
-+    },
-+
-+    _expirePPCache: function(ids)
-+    {
-+        this.ppfifo = this.ppfifo.without(ids);
-+        ids.each(this.ppcache.unset.bind(this.ppcache));
-+        // Preview pane cache size is 20 entries. Given that a reasonable guess
-+        // of an average e-mail size is 10 KB (including headers), also make
-+        // an estimate that the JSON data size will be approx. 10 KB. 200 KB
-+        // should be a fairly safe caching value for any recent browser.
-+        if (this.ppfifo.size() > 20) {
-+            this.ppcache.unset(this.ppfifo.shift());
-+        }
-+    },
-+
-+    // Labeling functions
-+    updateUnseenUID: function(r, setflag)
-+    {
-+        var sel, unseenset,
-+            unseen = 0;
-+        if (!r.bg) {
-+            return false;
-+        }
-+        unseenset = r.bg.match(this.unseen_regex);
-+        if ((setflag && unseenset) || (!setflag && !unseenset)) {
-+            return false;
-+        }
-+
-+        sel = this.viewport.createSelection('dataob', r);
-+        if (setflag) {
-+            this.viewport.updateFlag(sel, 'unseen', true);
-+            ++unseen;
-+        } else {
-+            this.viewport.updateFlag(sel, 'unseen', false);
-+            --unseen;
-+        }
-+
-+        return this.updateUnseenStatus(r.view, unseen);
-+    },
-+
-+    updateUnseenStatus: function(mbox, change)
-+    {
-+        if (change == 0) {
-+            return false;
-+        }
-+        var unseen = parseInt($(this.getFolderId(mbox)).readAttribute('u')) + change;
-+        this.viewport.setMetaData({ unseen: unseen });
-+        this.setFolderLabel(mbox, unseen);
-+        return true;
-+    },
-+
-+    setMessageListTitle: function()
-+    {
-+        var offset,
-+            rows = this.viewport.getMetaData('total_rows');
-+        if (rows > 0) {
-+            offset = this.viewport.currentOffset();
-+            $('msgHeader').update(DIMP.text.messages + ' ' + (offset + 1) + ' - ' + (Math.min(offset + this.viewport.getPageSize(), rows)) + ' ' + DIMP.text.of + ' ' + rows);
-+        } else {
-+            $('msgHeader').update(DIMP.text.nomessages);
-+        }
-+    },
-+
-+    setFolderLabel: function(f, unseen)
-+    {
-+        var elt, fid = this.getFolderId(f);
-+        elt = $(fid);
-+        if (!elt || !elt.hasAttribute('u')) {
-+            return;
-+        }
-+
-+        unseen = parseInt(unseen);
-+        elt.writeAttribute('u', unseen);
-+
-+        if (f == 'INBOX' && window.fluid) {
-+            window.fluid.setDockBadge(unseen ? unseen : '');
-+        }
-+
-+        $(fid + '_label').update((unseen > 0) ?
-+            new Element('STRONG').insert(elt.readAttribute('l')).insert(' ').insert(new Element('SPAN', { className: 'count', dir: 'ltr' }).insert('(' + unseen + ')')) :
-+            elt.readAttribute('l'));
-+
-+        if (this.folder == f) {
-+            this.updateTitle();
-+        }
-+    },
-+
-+    getFolderId: function(f)
-+    {
-+        return 'fld' + decodeURIComponent(f).replace(/_/g,'__').replace(/\W/g, '_');
-+    },
-+
-+    getSubFolderId: function(f)
-+    {
-+        return 'sub' + f;
-+    },
-+
-+    /* Folder list updates. */
-+    pollFolders: function()
-+    {
-+        // Reset poll folder counter.
-+        this.setPollFolders();
-+        var args = {};
-+        if (this.folder && $('dimpmain_folder').visible()) {
-+            args = this.viewport.addRequestParams({});
-+        }
-+        $('button_checkmail').setText('[' + DIMP.text.check + ']');
-+        DimpCore.doAction('PollFolders', args, [], this.bcache.get('pollFC') || this.bcache.set('pollFC', this._pollFoldersCallback.bind(this)));
-+    },
-+
-+    _pollFoldersCallback: function(r)
-+    {
-+        r = r.response;
-+        if (r.poll) {
-+            $H(r.poll).each(function(u) {
-+                this.setFolderLabel(u.key, u.value);
-+                if (this.viewport) {
-+                    this.viewport.setMetaData({ unseen: u.value }, u.key);
-+                }
-+            }, this);
-+        }
-+        if (r.quota) {
-+            $('quota').update(r.quota);
-+        }
-+        $('button_checkmail').setText(DIMP.text.getmail);
-+    },
-+
-+    setPollFolders: function()
-+    {
-+        if (DIMP.conf.refresh_time) {
-+            if (this.pollPE) {
-+                this.pollPE.stop();
-+            }
-+            // Don't cache - this code is only run once.
-+            this.pollPE = new PeriodicalExecuter(this.pollFolders.bind(this), DIMP.conf.refresh_time);
-+        }
-+    },
-+
-+    _portalCallback: function(r)
-+    {
-+        if (r.response.linkTags) {
-+            var head = $$('HEAD').first();
-+            r.response.linkTags.each(function(newLink) {
-+                var link = new Element('LINK', { type: 'text/css', rel: 'stylesheet', href: newLink.href });
-+                if (newLink.media) {
-+                    link.media = newLink.media;
-+                }
-+                head.insert(link);
-+            });
-+        }
-+        $('dimpmain_portal').update(r.response.portal);
-+
-+        /* Link portal block headers to the application. */
-+        $('dimpmain_portal').select('h1.header a').each(this.bcache.get('portalClkLink') || this.bcache.set('portalClkLink', function(d) {
-+            d.observe('click', function(e, d) {
-+                this.go('app:' + d.readAttribute('app'));
-+                e.stop();
-+            }.bindAsEventListener(this, d));
-+        }.bind(this)));
-+    },
-+
-+    /* Search filter functions. */
-+    _searchfilterOnKeyup: function()
-+    {
-+        if (this.searchobserve) {
-+            clearTimeout(this.searchobserve);
-+        }
-+        this.searchobserve = (this.bcache.get('searchfilterR') || this.bcache.set('searchfilterR', this.searchfilterRun.bind(this))).delay(0.5);
-+    },
-+
-+    searchfilterRun: function()
-+    {
-+        if (!this.viewport.isFiltering()) {
-+            this.filtertoggle = 1;
-+            this.fspecial = this.viewport.getMetaData('special');
-+        }
-+        this.viewport.runFilter($F('msgList_filter'));
-+    },
-+
-+    _searchfilterOnFocus: function()
-+    {
-+        var q = $('qoptions');
-+
-+        if ($('msgList_filter').hasClassName('msgFilterDefault')) {
-+            this._setFilterText(false);
-+        }
-+
-+        if (!q.visible()) {
-+            $('sf_current').update(this.viewport.getMetaData('label'));
-+            this._setSearchfilterParams(this.viewport.getMetaData('special') ? 'to' : 'from', 'msg');
-+            this._setSearchfilterParams('current', 'folder');
-+            q.show();
-+            this.viewport.onResize();
-+        }
-+    },
-+
-+    _searchfilterOnBlur: function()
-+    {
-+        if (!$F('msgList_filter')) {
-+            this._setFilterText(true);
-+        }
-+    },
-+
-+    // reset = (boolean) TODO
-+    searchfilterClear: function(reset)
-+    {
-+        if (!$('qoptions').visible()) {
-+            return;
-+        }
-+        if (this.searchobserve) {
-+            clearTimeout(this.searchobserve);
-+            this.searchobserve = null;
-+        }
-+        this._setFilterText(true);
-+        $('qoptions').hide();
-+        this.filtertoggle = 2;
-+        this.resetSelected();
-+        this.viewport.onResize(reset);
-+        this.viewport.stopFilter(reset);
-+    },
-+
-+    // d = (boolean) Deactivate filter input?
-+    _setFilterText: function(d)
-+    {
-+        var mf = $('msgList_filter');
-+        if (d) {
-+            mf.setValue(DIMP.text.search);
-+            mf.addClassName('msgFilterDefault');
-+        } else {
-+            mf.setValue('');
-+            mf.removeClassName('msgFilterDefault');
-+        }
-+    },
-+
-+    // type = 'folder' or 'msg'
-+    _setSearchfilterParams: function(id, type)
-+    {
-+        var c = (type == 'folder') ? this.sfiltersfolder : this.sfilters;
-+        c.keys().each(function(i) {
-+            $(i).writeAttribute('className', (id == c.get(i)) ? 'qselected' : '');
-+        });
-+    },
-+
-+    updateSearchfilter: function(id, type)
-+    {
-+        this._setSearchfilterParams(id, type);
-+        if ($F('msgList_filter')) {
-+            this.viewport.runFilter();
-+        }
-+    },
-+
-+    _addSearchfilterParams: function()
-+    {
-+        var sf = this.sfiltersfolder.keys().find(function(s) {
-+                return $(s).hasClassName('qselected');
-+            });
-+        return { searchfolder: this.sfiltersfolder.get(sf), searchmsg: this.sfilters.get(this._getSearchfilterField()) };
-+    },
-+
-+    _getSearchfilterField: function()
-+    {
-+        return this.sfilters.keys().find(function(s) {
-+            return $(s).hasClassName('qselected');
-+        });
-+    },
-+
-+    /* Enable/Disable DIMP action buttons as needed. */
-+    toggleButtons: function()
-+    {
-+        var disable = (this.selectedCount() == 0);
-+        DimpCore.buttons.each(function(b) {
-+            var elt = $(b);
-+            if (elt) {
-+                [ elt.up() ].invoke(disable ? 'addClassName' : 'removeClassName', 'disabled');
-+                DimpCore.DMenu.disable(b + '_img', true, disable);
-+            }
-+        });
-+    },
-+
-+    /* Drag/Drop handler. */
-+    _folderDropHandler: function(drop, drag)
-+    {
-+        var dropbase, sel, uids,
-+            foldername = drop.readAttribute('mbox'),
-+            ftype = drop.readAttribute('ftype');
-+
-+        if (drag.hasClassName('folder')) {
-+            dropbase = (drop == $('dropbase'));
-+            if (dropbase ||
-+                (ftype != 'special' && !this.isSubfolder(drag, drop))) {
-+                DimpCore.doAction('RenameFolder', { old_name: drag.readAttribute('mbox'), new_parent: dropbase ? '' : foldername, new_name: drag.readAttribute('l') }, [], this.bcache.get('folderC') || this.bcache.set('folderC', this._folderCallback.bind(this)));
-+            }
-+        } else if (ftype != 'container') {
-+            sel = this.viewport.getSelected();
-+
-+            if (sel.size()) {
-+                // Dragging multiple selected messages.
-+                uids = sel;
-+            } else if (drag.readAttribute('mbox') != foldername) {
-+                // Dragging a single unselected message.
-+                uids = this.viewport.createSelection('domid', drag.id);
-+            }
-+
-+            // Don't allow drag/drop to the current folder.
-+            if (uids.size() && this.folder != foldername) {
-+                this.viewport.updateFlag(uids, 'deletedmsg', true);
-+                DimpCore.doAction('MoveMessage', this.viewport.addRequestParams({ tofld: foldername }), DimpCore.toUIDArray(uids), this.bcache.get('deleteC') || this.bcache.set('deleteC', this._deleteCallback.bind(this)));
-+            }
-+        }
-+    },
-+
-+    _dragCaption: function()
-+    {
-+        var cnt = this.selectedCount();
-+        return cnt + ' ' + (cnt == 1 ? DIMP.text.message : DIMP.text.messages);
-+    },
-+
-+    /* Keydown event handler */
-+    _keydownHandler: function(e)
-+    {
-+        // Only catch keyboard shortcuts in message list view. Disable catching
-+        // when in form elements or the RedBox overlay is visible.
-+        if (!$('dimpmain_folder').visible() ||
-+            e.findElement('FORM') ||
-+            RedBox.overlayVisible()) {
-+            return;
-+        }
-+
-+        var co, ps, r, row, rowoff,
-+            kc = e.keyCode || e.charCode,
-+            sel = this.viewport.getSelected();
-+
-+        switch (kc) {
-+        case Event.KEY_DELETE:
-+        case Event.KEY_BACKSPACE:
-+            r = sel.get('dataob');
-+            if (e.shiftKey) {
-+                this.moveSelected((r.last().rownum == this.viewport.getMetaData('total_rows')) ? (r.first().rownum - 1) : (r.last().rownum + 1), true);
-+            }
-+            this.flag('deleted', r);
-+            e.stop();
-+            break;
-+
-+        case Event.KEY_UP:
-+        case Event.KEY_DOWN:
-+            if (e.shiftKey && this.lastrow != -1) {
-+                row = this.viewport.createSelection('rownum', this.lastrow + ((kc == Event.KEY_UP) ? -1 : 1));
-+                if (row.size()) {
-+                    row = row.get('dataob').first();
-+                    this.viewport.scrollTo(row.rownum);
-+                    this.msgSelect(row.domid, { shift: true });
-+                }
-+            } else {
-+                this.moveSelected(kc == Event.KEY_UP ? -1 : 1);
-+            }
-+            e.stop();
-+            break;
-+
-+        case Event.KEY_PAGEUP:
-+        case Event.KEY_PAGEDOWN:
-+            if (!e.ctrlKey && !e.shiftKey && !e.altKey && !e.metaKey) {
-+                ps = this.viewport.getPageSize() - 1;
-+                move = ps * (kc == Event.KEY_PAGEUP ? -1 : 1);
-+                if (sel.size() == 1) {
-+                    co = this.viewport.currentOffset();
-+                    rowoff = sel.get('rownum').first() - 1;
-+                    switch (kc) {
-+                    case Event.KEY_PAGEUP:
-+                        if (co != rowoff) {
-+                            move = co - rowoff;
-+                        }
-+                        break;
-+
-+                    case Event.KEY_PAGEDOWN:
-+                        if ((co + ps) != rowoff) {
-+                            move = co + ps - rowoff;
-+                        }
-+                        break;
-+                    }
-+                }
-+                this.moveSelected(move);
-+                e.stop();
-+            }
-+            break;
-+
-+        case Event.KEY_HOME:
-+        case Event.KEY_END:
-+            this.moveSelected(kc == Event.KEY_HOME ? 1 : this.viewport.getMetaData('total_rows'), true);
-+            e.stop();
-+            break;
-+
-+        case Event.KEY_RETURN:
-+            if (!e.element().match('input')) {
-+                // Popup message window if single message is selected.
-+                if (sel.size() == 1) {
-+                    this.msgWindow(sel.get('dataob').first());
-+                }
-+            }
-+            e.stop();
-+            break;
-+
-+        case 65: // A
-+        case 97: // a
-+            if (e.ctrlKey) {
-+                this.selectAll();
-+                e.stop();
-+            }
-+            break;
-+        }
-+    },
-+
-+    /* Handle rename folder actions. */
-+    renameFolder: function(folder)
-+    {
-+        if (Object.isUndefined(folder)) {
-+            return;
-+        }
-+
-+        folder = $(folder);
-+        var n = this._createFolderForm(function(e) { this._folderAction(folder, e, 'rename'); return false; }.bindAsEventListener(this), DIMP.text.rename_prompt);
-+        n.down('input').setValue(folder.readAttribute('l'));
-+    },
-+
-+    /* Handle insert folder actions. */
-+    createBaseFolder: function()
-+    {
-+        this._createFolderForm(function(e) { this._folderAction('', e, 'create'); return false; }.bindAsEventListener(this), DIMP.text.create_prompt);
-+    },
-+
-+    createSubFolder: function(folder)
-+    {
-+        if (Object.isUndefined(folder)) {
-+            return false;
-+        }
-+
-+        this._createFolderForm(function(e) { this._folderAction($(folder), e, 'createsub'); return false; }.bindAsEventListener(this), DIMP.text.createsub_prompt);
-+    },
-+
-+    _createFolderForm: function(action, text)
-+    {
-+        var n = new Element('FORM', { action: '#', id: 'RB_folder' }).insert(
-+                    new Element('P').insert(text)
-+                ).insert(
-+                    new Element('INPUT', { type: 'text', size: 15 })
-+                ).insert(
-+                    new Element('INPUT', { type: 'button', className: 'button', value: DIMP.text.ok }).observe('click', action)
-+                ).insert(
-+                    new Element('INPUT', { type: 'button', className: 'button', value: DIMP.text.cancel }).observe('click', this.bcache.get('closeRB') || this.bcache.set('closeRB', this._closeRedBox.bind(this)))
-+                ).observe('keydown', function(e) { if ((e.keyCode || e.charCode) == Event.KEY_RETURN) { e.stop(); action(e); } });
-+
-+        RedBox.overlay = true;
-+        RedBox.onDisplay = Form.focusFirstElement.curry(n);
-+        RedBox.showHtml(n);
-+        return n;
-+    },
-+
-+    _closeRedBox: function()
-+    {
-+        var c = RedBox.getWindowContents();
-+        DimpCore.addGC([ c, c.descendants() ].flatten());
-+        RedBox.close();
-+    },
-+
-+    _folderAction: function(folder, e, mode)
-+    {
-+        this._closeRedBox();
-+
-+        var action, params, val,
-+            form = e.findElement('form');
-+        val = $F(form.down('input'));
-+
-+        if (val) {
-+            switch (mode) {
-+            case 'rename':
-+                if (folder.readAttribute('l') != val) {
-+                    action = 'RenameFolder';
-+                    params = { old_name: folder.readAttribute('mbox'),
-+                               new_parent: folder.up().hasClassName('folderlist') ? '' : folder.up(1).previous().readAttribute('mbox'),
-+                               new_name: val };
-+                }
-+                break;
-+
-+            case 'create':
-+            case 'createsub':
-+                action = 'CreateFolder';
-+                params = { folder: val };
-+                if (mode == 'createsub') {
-+                    params.parent = folder.readAttribute('mbox');
-+                }
-+                break;
-+            }
-+            if (action) {
-+                DimpCore.doAction(action, params, [], this.bcache.get('folderC') || this.bcache.set('folderC', this._folderCallback.bind(this)));
-+            }
-+        }
-+    },
-+
-+    /* Folder action callback functions. */
-+    _folderCallback: function(r)
-+    {
-+        r = r.response;
-+        r.d.each(this.deleteFolder.bind(this));
-+        r.c.each(this.changeFolder.bind(this));
-+        r.a.each(this.createFolder.bind(this));
-+    },
-+
-+    _deleteCallback: function(r)
-+    {
-+        this.msgListLoading(false);
-+        this._pollFoldersCallback(r);
-+
-+        if (!r.response.uids ||
-+            r.response.folder != this.folder) {
-+            return;
-+        }
-+
-+        var search = this.viewport.getViewportSelection().search({ view: { equal: [ r.response.folder ] }, imapuid: { equal: r.response.uids[r.response.folder] } });
-+        if (search.size()) {
-+            if (r.response.remove) {
-+                this.viewport.remove(search, { cacheid: r.response.cacheid, noupdate: r.response.viewport });
-+                this._expirePPCache(search.get('uid'));
-+            } else {
-+                // Need this to catch spam deletions.
-+                this.viewport.updateFlag(search, 'deletedmsg', true);
-+            }
-+        }
-+    },
-+
-+    _emptyFolderCallback: function(r)
-+    {
-+        if (r.response.mbox) {
-+            if (this.folder == r.response.mbox) {
-+                this.viewport.reload();
-+                this.clearPreviewPane();
-+            }
-+            this.setFolderLabel(r.response.mbox, 0);
-+        }
-+    },
-+
-+    _flagAllCallback: function(r)
-+    {
-+        if (r.response.mbox) {
-+            this.setFolderLabel(r.response.mbox, r.response.u);
-+        }
-+    },
-+
-+    _folderLoadCallback: function(r)
-+    {
-+        this._folderCallback(r);
-+
-+        var elts = $('specialfolders', 'normalfolders').compact(),
-+            nf = $('normalfolders'),
-+            nfheight = nf.getStyle('max-height');
-+
-+        elts.invoke('observe', 'click', this._handleFolderMouseEvent.bindAsEventListener(this, 'click'));
-+        elts.invoke('observe', 'mouseover', this._handleFolderMouseEvent.bindAsEventListener(this, 'over'));
-+        if (DIMP.conf.is_ie6) {
-+            elts.invoke('observe', 'mouseout', this._handleFolderMouseEvent.bindAsEventListener(this, 'out'));
-+        }
-+
-+        $('foldersLoading').hide();
-+        $('foldersSidebar').show();
-+
-+        // Fix for IE6 - which doesn't support max-height.  We need to search
-+        // for height: 0px instead (comment in IE 6 CSS explains this is
-+        // needed for auto sizing).
-+        if (nfheight !== null ||
-+            (Prototype.Browser.IE &&
-+             Object.isUndefined(nfheight) &&
-+             (nf.getStyle('height') == '0px'))) {
-+            this._sizeFolderlist();
-+            Event.observe(window, 'resize', this._sizeFolderlist.bind(this));
-+        }
-+
-+        if (r.response.quota) {
-+            $('quota').update(r.response.quota);
-+        }
-+    },
-+
-+    _handleFolderMouseEvent: function(e, action)
-+    {
-+        var type,
-+            elt = e.element(),
-+            li = elt.up('.folder') || elt.up('.custom');
-+        if (!li) {
-+            return;
-+        }
-+        type = li.readAttribute('ftype');
-+
-+        switch (action) {
-+        case 'over':
-+            if (DIMP.conf.is_ie6) {
-+                li.addClassName('over');
-+            }
-+            if (type && !this.mo_sidebar.get(li.id)) {
-+                DimpCore.addMouseEvents({ id: li.id, type: type });
-+                this.mo_sidebar.set(li.id, 1);
-+            }
-+            break;
-+
-+        case 'out':
-+            li.removeClassName('over');
-+            break;
-+
-+        case 'click':
-+            if (elt.hasClassName('exp') || elt.hasClassName('col')) {
-+                this._toggleSubFolder(li.id, 'tog');
-+            } else {
-+                switch (type) {
-+                case 'container':
-+                    e.stop();
-+                    break;
-+
-+                case 'folder':
-+                case 'special':
-+                    e.stop();
-+                    return this.go('folder:' + li.readAttribute('mbox'));
-+                    break;
-+                }
-+            }
-+            break;
-+        }
-+    },
-+
-+    _toggleSubFolder: function(base, mode)
-+    {
-+        base = $(base);
-+        var s = $(this.getSubFolderId(base.id));
-+        if (s &&
-+            (mode == 'tog' ||
-+             (mode == 'exp' && !s.visible()) ||
-+             (mode == 'col' && s.visible()))) {
-+            base.firstDescendant().writeAttribute({ className: s.toggle().visible() ? 'col' : 'exp' });
-+        }
-+        if (base.descendantOf('specialfolders')) {
-+            this._sizeFolderlist();
-+        }
-+    },
-+
-+    // Folder actions.
-+    // For format of the ob object, see DIMP::_createFolderElt().
-+    createFolder: function(ob)
-+    {
-+        var div, f_node, li, ll, parent_e,
-+            fid = this.getFolderId(ob.m),
-+            mbox = decodeURIComponent(ob.m),
-+            submboxid = this.getSubFolderId(fid),
-+            submbox = $(submboxid);
-+
-+        li = new Element('LI', { className: 'folder', id: fid, l: ob.l, mbox: mbox, ftype: ((ob.co) ? 'container' : ((ob.s) ? 'special' : 'folder')) });
-+
-+        div = new Element('DIV', { className: ob.cl || 'base', id: fid + '_div' });
-+        if (ob.i) {
-+            div.setStyle({ backgroundImage: 'url("' + ob.i + '")' });
-+        }
-+        if (ob.ch) {
-+            div.writeAttribute({ className: 'exp' }).observe('mouseover', this.bcache.get('mo_folder') || this.bcache.set('mo_folder', function(e) {
-+                e = e.element();
-+                if (DragDrop.Drags.drag && e.hasClassName('exp')) {
-+                    this._toggleSubFolder(e.up(), 'exp');
-+                }
-+            }.bindAsEventListener(this)));
-+        }
-+
-+        li.insert(div).insert(new Element('A', { id: fid + '_label', title: ob.l }).insert(ob.l));
-+
-+        // Now walk through the parent <ul> to find the right place to
-+        // insert the new folder.
-+        if (submbox) {
-+            if (submbox.insert({ before: li }).visible()) {
-+                // If an expanded parent mailbox was deleted, we need to toggle
-+                // the icon accordingly.
-+                div.removeClassName('exp').addClassName('col');
-+            }
-+        } else {
-+            if (ob.s) {
-+                parent_e = $('specialfolders');
-+            } else {
-+                parent_e = $(this.getSubFolderId(this.getFolderId(ob.pa)));
-+                parent_e = (parent_e) ? parent_e.down('UL') : $('normalfolders');
-+            }
-+
-+            ll = mbox.toLowerCase();
-+            f_node = parent_e.childElements().find(function(node) {
-+                var nodembox = node.readAttribute('mbox');
-+                return nodembox &&
-+                       (!ob.s || nodembox != 'INBOX') &&
-+                       (ll < nodembox.toLowerCase());
-+            });
-+
-+            if (f_node) {
-+                f_node.insert({ before: li });
-+            } else {
-+                parent_e.insert(li);
-+            }
-+
-+            // Make sure the sub<mbox> ul is created if necessary.
-+            if (ob.ch) {
-+                li.insert({ after: new Element('LI', { className: 'subfolders', id: submboxid }).insert(new Element('UL')).hide() });
-+            }
-+        }
-+
-+        // Make the new folder a drop target.
-+        new Drop(li, this._folderDropConfig);
-+
-+        // Check for unseen messages
-+        if (ob.po) {
-+            li.writeAttribute('u', '');
-+            this.setFolderLabel(mbox, ob.u);
-+        }
-+    },
-+
-+    deleteFolder: function(folder)
-+    {
-+        var f = decodeURIComponent(folder), fid;
-+        if (this.folder == f) {
-+            this.go('folder:INBOX');
-+        }
-+
-+        fid = this.getFolderId(folder);
-+        this.deleteFolderElt(fid, true);
-+    },
-+
-+    changeFolder: function(ob)
-+    {
-+        var fid = this.getFolderId(ob.m),
-+            fdiv = $(fid + '_div'),
-+            oldexpand = fdiv && fdiv.hasClassName('col');
-+        this.deleteFolderElt(fid, !ob.ch);
-+        if (ob.co && this.folder == ob.m) {
-+            this.go('folder:INBOX');
-+        }
-+        this.createFolder(ob);
-+        if (ob.ch && oldexpand) {
-+            fdiv.removeClassName('exp').addClassName('col');
-+        }
-+    },
-+
-+    deleteFolderElt: function(fid, sub)
-+    {
-+        var f = $(fid);
-+        DimpCore.addGC($(f, fid + '_div', fid + '_label'));
-+        if (sub) {
-+            var submbox = $(this.getSubFolderId(fid));
-+            if (submbox) {
-+                submbox.remove();
-+            }
-+        }
-+        [ DragDrop.Drags.get_drag(fid), DragDrop.Drops.get_drop(fid) ].compact().invoke('destroy');
-+        DimpCore.removeMouseEvents(f);
-+        this.mo_sidebar.unset(fid, 1);
-+        DimpCore.addGC(f);
-+        if (this.viewport) {
-+            this.viewport.deleteView(fid);
-+        }
-+        f.remove();
-+    },
-+
-+    _sizeFolderlist: function()
-+    {
-+        var nf = $('normalfolders');
-+        nf.setStyle({ height: (document.viewport.getHeight() - nf.cumulativeOffset()[1] - 10) + 'px' });
-+    },
-+
-+    /* Flag actions for message list. */
-+    flag: function(action, index, folder)
-+    {
-+        var actionCall, args, vs,
-+            obs = [],
-+            unseenstatus = 1;
-+
-+        if (index) {
-+            if (Object.isUndefined(folder)) {
-+                vs = this.viewport.createSelection('dataob', index);
-+            } else {
-+                vs = this.viewport.getViewportSelection().search({ imapuid: { equal: [ index ] }, view: { equal: [ folder ] } });
-+                if (!vs.size() && folder != this.folder) {
-+                    vs = this.viewport.getViewportSelection(folder).search({ imapuid: { equal: [ index ] } });
-+                }
-+            }
-+        } else {
-+            vs = this.viewport.getSelected();
-+        }
-+
-+        switch (action) {
-+        case 'allUnseen':
-+        case 'allSeen':
-+            DimpCore.doAction((action == 'allUnseen') ? 'MarkFolderUnseen' : 'MarkFolderSeen', { folder: folder }, [], this.bcache.get('flagAC') || this.bcache.set('flagAC', this._flagAllCallback.bind(this)));
-+            if (folder == this.folder) {
-+                this.viewport.updateFlag(this.createSelection('rownum', $A($R(1, this.viewport.getMetaData('total_rows')))), 'unseen', action == 'allUnseen');
-+            }
-+            break;
-+
-+        case 'deleted':
-+        case 'undeleted':
-+        case 'spam':
-+        case 'ham':
-+        case 'blacklist':
-+        case 'whitelist':
-+            if (!vs.size()) {
-+                break;
-+            }
-+
-+            // 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).
-+            if (action == 'deleted') {
-+                vs = vs.search({ isdel: { not: [ true ] } });
-+                if (!vs.size()) {
-+                    break;
-+                }
-+                vs.set({ isdel: true });
-+            } else if (action == 'undeleted') {
-+                vs.set({ isdel: false });
-+            }
-+
-+            args = this.viewport.addRequestParams({});
-+            if (action == 'deleted' || action == 'undeleted') {
-+                this.viewport.updateFlag(vs, 'deletedmsg', action == 'deleted');            }
-+
-+            if (action == 'undeleted') {
-+                DimpCore.doAction('UndeleteMessage', args, DimpCore.toUIDArray(vs));
-+            } else {
-+                actionCall = { deleted: 'DeleteMessage', spam: 'ReportSpam', ham: 'ReportHam', blacklist: 'Blacklist', whitelist: 'Whitelist' };
-+                // This needs to be synchronous Ajax if we are calling from a
-+                // popup window because Mozilla will not correctly call the
-+                // callback function if the calling window has been closed.
-+                DimpCore.doAction(actionCall[action], args, DimpCore.toUIDArray(vs), this.bcache.get('deleteC') || this.bcache.set('deleteC', this._deleteCallback.bind(this)), { asynchronous: !(index && folder) });
-+
-+                // If reporting spam, to indicate to the user that something is
-+                // happening (since spam reporting may not be instantaneous).
-+                if (action == 'spam' || action == 'ham') {
-+                    this.msgListLoading(true);
-+                }
-+            }
-+            break;
-+
-+        case 'unseen':
-+        case 'seen':
-+            if (!vs.size()) {
-+                break;
-+            }
-+            args = { folder: this.folder, messageFlag: '-seen' };
-+            if (action == 'seen') {
-+                unseenstatus = 0;
-+                args.messageFlag = 'seen';
-+            }
-+            vs.get('dataob').each(function(s) {
-+                if (this.updateUnseenUID(s, unseenstatus)) {
-+                    obs.push(s);
-+                }
-+            }, this);
-+
-+            if (obs.size()) {
-+                DimpCore.doAction('MarkMessage', args, DimpCore.toUIDArray(this.viewport.createSelection('dataob', obs)));
-+            }
-+            break;
-+
-+        case 'flagged':
-+        case 'clear':
-+            if (!vs.size()) {
-+                break;
-+            }
-+            args = {
-+                folder: this.folder,
-+                messageFlag: ((action == 'flagged') ? 'flagged' : '-flagged')
-+            };
-+            this.viewport.updateFlag(vs, 'flagged', action == 'flagged');
-+            DimpCore.doAction('MarkMessage', args, DimpCore.toUIDArray(vs));
-+            break;
-+
-+        case 'answered':
-+            this.viewport.updateFlag(vs, 'answered', true);
-+            this.viewport.updateFlag(vs, 'flagged', false);
-+            break;
-+        }
-+    },
-+
-+    /* Miscellaneous folder actions. */
-+    purgeDeleted: function()
-+    {
-+        DimpCore.doAction('PurgeDeleted', this.viewport.addRequestParams({}), [], this.bcache.get('deleteC') || this.bcache.set('deleteC', this._deleteCallback.bind(this)));
-+    },
-+
-+    modifyPollFolder: function(folder, add)
-+    {
-+        DimpCore.doAction('ModifyPollFolder', { folder: folder, add: (add) ? 1 : 0 }, [], this.bcache.get('modifyPFC') || this.bcache.set('modifyPFC', this._modifyPollFolderCallback.bind(this)));
-+    },
-+
-+    _modifyPollFolderCallback: function(r)
-+    {
-+        r = r.response;
-+        var f = r.folder, fid, p = { response: { poll: {} } };
-+        fid = $(this.getFolderId(f));
-+
-+        if (r.add) {
-+            p.response.poll[f] = r.poll.u;
-+            fid.writeAttribute('u', 0);
-+        } else {
-+            p.response.poll[f] = 0;
-+        }
-+
-+        this._pollFoldersCallback(p);
-+
-+        if (!r.add) {
-+            fid.removeAttribute('u');
-+        }
-+    },
-+
-+    msgListLoading: function(show)
-+    {
-+        var ml_offset;
-+
-+        if (this.fl_visible != show) {
-+            this.fl_visible = show;
-+            if (show) {
-+                ml_offset = $('msgList').positionedOffset();
-+                $('folderLoading').setStyle({ position: 'absolute', top: (ml_offset.top + 10) + 'px', left: (ml_offset.left + 10) + 'px' });
-+                Effect.Appear('folderLoading', { duration: 0.2 });
-+                $(document.body).setStyle({ cursor: 'progress' });
-+            } else {
-+                Effect.Fade('folderLoading', { duration: 0.2 });
-+                $(document.body).setStyle({ cursor: 'default' });
-+            }
-+        }
-+    },
-+
-+    // p = (element) Parent element
-+    // c = (element) Child element
-+    isSubfolder: function(p, c)
-+    {
-+        var sf = $(this.getSubFolderId(p.readAttribute('id')));
-+        return sf && c.descendantOf(sf);
-+    },
-+
-+    /* Onload function. */
-+    _onLoad: function() {
-+        var C = DimpCore.clickObserveHandler, tmp;
-+
-+        if (Horde.dhtmlHistory.initialize()) {
-+            Horde.dhtmlHistory.addListener(this.go.bind(this));
-+        }
-+
-+        this._setFilterText(true);
-+
-+        /* Initialize the starting page if necessary. addListener() will have
-+         * already fired if there is a current location so only do a go()
-+         * call if there is no current location. */
-+        if (!Horde.dhtmlHistory.getCurrentLocation()) {
-+            if (DIMP.conf.login_view == 'inbox') {
-+                this.go('folder:INBOX');
-+            } else {
-+                this.go('portal');
-+                if (DIMP.conf.background_inbox) {
-+                    this.loadFolder('INBOX', true);
-+                }
-+            }
-+        }
-+
-+        /* Add popdown menus. */
-+        DimpCore.addPopdown('button_reply', 'reply');
-+        DimpCore.DMenu.disable('button_reply_img', true, true);
-+        DimpCore.addPopdown('button_forward', 'forward');
-+        DimpCore.DMenu.disable('button_forward_img', true, true);
-+        DimpCore.addPopdown('button_other', 'otheractions');
-+
-+        /* Set up click event observers for elements on main page. */
-+        tmp = $('logo');
-+        if (tmp.visible()) {
-+            C({ d: tmp.down('a'), f: this.go.bind(this, 'portal') });
-+        }
-+
-+        tmp = $('dimpbarActions');
-+        C({ d: tmp.down('.composelink'), f: DimpCore.compose.bind(DimpCore, 'new') });
-+        C({ d: tmp.down('.refreshlink'), f: this.pollFolders.bind(this) });
-+
-+        tmp = $('serviceActions');
-+        [ 'portal', 'options' ].each(function(a) {
-+            var d = $('app' + a);
-+            if (d) {
-+                C({ d: d, f: this.go.bind(this, a) });
-+            }
-+        }, this);
-+        tmp = $('applogout');
-+        if (tmp) {
-+            C({ d: tmp, f: DimpCore.logout.bind(DimpCore) });
-+        }
-+
-+        tmp = $('applicationfolders');
-+        if (tmp) {
-+            tmp.select('ul li.custom a').each(function(s) {
-+                C({ d: s, f: this.go.bind(this, 'app:' + s.readAttribute('app')) });
-+            }, this);
-+        }
-+
-+        C({ d: $('newfolder'), f: this.createBaseFolder.bind(this) });
-+        new Drop('dropbase', this._folderDropConfig);
-+        tmp = $('hometab');
-+        if (tmp) {
-+            C({ d: tmp, f: this.go.bind(this, 'portal') });
-+        }
-+        $('tabbar').select('a.applicationtab').each(function(a) {
-+            C({ d: a, f: this.go.bind(this, 'app:' + a.readAttribute('app')) });
-+        }, this);
-+        C({ d: $('button_reply'), f: this.composeMailbox.bind(this, 'reply'), ns: true });
-+        C({ d: $('button_forward'), f: this.composeMailbox.bind(this, DIMP.conf.forward_default), ns: true });
-+        [ 'spam', 'ham', 'deleted' ].each(function(a) {
-+            var d = $('button_' + a);
-+            if (d) {
-+                C({ d: d, f: this.flag.bind(this, a) });
-+            }
-+        }, this);
-+        C({ d: $('button_compose'), f: DimpCore.compose.bind(DimpCore, 'new') });
-+        C({ d: $('button_other'), f: function(e) { DimpCore.DMenu.trigger(e.findElement('A').next(), true); }, p: true });
-+        C({ d: $('qoptions').down('.qclose a'), f: this.searchfilterClear.bind(this, false) });
-+        [ 'all', 'current' ].each(function(a) {
-+            var d = $('sf_' + a);
-+            if (d) {
-+                C({ d: d, f: this.updateSearchfilter.bind(this, a, 'folder') });
-+            }
-+        }, this);
-+        [ 'msgall', 'from', 'to', 'subject' ].each(function(a) {
-+            C({ d: $('sf_' + a), f: this.updateSearchfilter.bind(this, a, 'msg') });
-+        }, this);
-+        C({ d: $('msglistHeader'), f: this.sort.bind(this), p: true });
-+        C({ d: $('ctx_folder_create'), f: function() { this.createSubFolder(DimpCore.DMenu.element()); }.bind(this), ns: true });
-+        C({ d: $('ctx_folder_rename'), f: function() { this.renameFolder(DimpCore.DMenu.element()); }.bind(this), ns: true });
-+        C({ d: $('ctx_folder_empty'), f: function() { if (window.confirm(DIMP.text.empty_folder)) { DimpCore.doAction('EmptyFolder', { folder: DimpCore.DMenu.element().readAttribute('mbox') }, [], this._emptyFolderCallback.bind(this)); } }.bind(this), ns: true });
-+        C({ d: $('ctx_folder_delete'), f: function() { if (window.confirm(DIMP.text.delete_folder)) { DimpCore.doAction('DeleteFolder', { folder: DimpCore.DMenu.element().readAttribute('mbox') }, [], this.bcache.get('folderC') || this.bcache.set('folderC', this._folderCallback.bind(this))); } }.bind(this), ns: true });
-+        [ 'ctx_folder_seen', 'ctx_folder_unseen' ].each(function(a) {
-+            C({ d: $(a), f: function(type) { this.flag(type, null, DimpCore.DMenu.element().readAttribute('mbox')); }.bind(this, a == 'ctx_folder_seen' ? 'allSeen' : 'allUnseen'), ns: true });
-+        }, this);
-+        [ 'ctx_folder_poll', 'ctx_folder_nopoll' ].each(function(a) {
-+            C({ d: $(a), f: function(modify) { this.modifyPollFolder(DimpCore.DMenu.element().readAttribute('mbox'), modify); }.bind(this, a == 'ctx_folder_poll'), ns: true });
-+        }, this);
-+        C({ d: $('ctx_container_create'), f: function() { this.createSubFolder(DimpCore.DMenu.element()); }.bind(this), ns: true });
-+        C({ d: $('ctx_container_rename'), f: function() { this.renameFolder(DimpCore.DMenu.element()); }.bind(this), ns: true });
-+        [ 'reply', 'reply_all', 'reply_list', 'forward_all', 'forward_body', 'forward_attachments' ].each(function(a) {
-+            C({ d: $('ctx_message_' + a), f: this.composeMailbox.bind(this, a), ns: true });
-+        }, this);
-+        [ 'seen', 'unseen', 'flagged', 'clear', 'spam', 'ham', 'blacklist', 'whitelist', 'deleted', 'undeleted' ].each(function(a) {
-+            var d = $('ctx_message_' + a);
-+            if (d) {
-+                C({ d: d, f: this.flag.bind(this, a), ns: true });
-+            }
-+        }, this);
-+        C({ d: $('ctx_draft_resume'), f: this.composeMailbox.bind(this, 'resume') });
-+        [ 'flagged', 'clear', 'deleted', 'undeleted' ].each(function(a) {
-+            var d = $('ctx_draft_' + a);
-+            if (d) {
-+                C({ d: d, f: this.flag.bind(this, a), ns: true });
-+            }
-+        }, this);
-+        [ 'reply', 'reply_all', 'reply_list' ].each(function(a) {
-+            C({ d: $('ctx_reply_' + a), f: this.composeMailbox.bind(this, a), ns: true });
-+        }, this);
-+        [ 'forward_all', 'forward_body', 'forward_attachments' ].each(function(a) {
-+            C({ d: $('ctx_forward_' + a), f: this.composeMailbox.bind(this, a), ns: true });
-+        }, this);
-+        C({ d: $('previewtoggle'), f: this.togglePreviewPane.bind(this), ns: true });
-+        [ 'seen', 'unseen', 'flagged', 'clear', 'blacklist', 'whitelist', 'undeleted' ].each(function(a) {
-+            var d = $('oa_' + a);
-+            if (d) {
-+                C({ d: d, f: this.flag.bind(this, a), ns: true });
-+            }
-+        }, this);
-+        C({ d: $('oa_selectall'), f: this.selectAll.bind(this), ns: true });
-+
-+        tmp = $('oa_purge_deleted');
-+        if (tmp) {
-+            C({ d: tmp, f: this.purgeDeleted.bind(this), ns: true });
-+        }
-+
-+        $('expandHeaders', 'collapseHeaders').each(function(a) {
-+            C({ d: a, f: function() { $('msgHeadersColl', 'msgHeaders').invoke('toggle'); }, ns: true });
-+        }, this);
-+        $('msg_newwin', 'msg_newwin_options').compact().each(function(a) {
-+            C({ d: a, f: function() { this.msgWindow(this.viewport.getViewportSelection().search({ imapuid: { equal: [ DIMP.conf.msg_index ] } , view: { equal: [ DIMP.conf.msg_folder ] } }).get('dataob').first()); }.bind(this) });
-+        }, this);
-+        DimpCore.messageOnLoad();
-+        this._resizeIE6();
-+    },
-+
-+    // IE 6 width fixes (See Bug #6793)
-+    _resizeIE6: function()
-+    {
-+        if (DIMP.conf.is_ie6) {
-+            var tmp = parseInt($('sidebarPanel').getStyle('width'), 10),
-+                tmp1 = document.viewport.getWidth() - tmp - 30;
-+            $('normalfolders').setStyle({ width: tmp + 'px' });
-+            $('dimpmain').setStyle({ width: tmp1 + 'px' });
-+            $('msglist').setStyle({ width: (tmp1 - 5) + 'px' });
-+            $('msgBody').setStyle({ width: (tmp1 - 25) + 'px' });
-+            tmp = $('dimpmain_portal').down('IFRAME');
-+            if (tmp) {
-+                this._resizeIE6Iframe(tmp);
-+            }
-+        }
-+    },
-+
-+    _resizeIE6Iframe: function(iframe)
-+    {
-+        if (DIMP.conf.is_ie6) {
-+            iframe.setStyle({ width: $('dimpmain').getStyle('width'), height: (document.viewport.getHeight() - 20) + 'px' });
-+        }
-+    }
-+};
-+
-+/* Need to add after DimpBase is defined. */
-+DimpBase._msgDragConfig = {
-+    scroll: 'normalfolders',
-+    threshold: 5,
-+    caption: DimpBase._dragCaption.bind(DimpBase),
-+    onStart: function(d, e) {
-+        var args = { right: e.isRightClick() },
-+            id = d.element.id;
-+
-+        d.selectIfNoDrag = false;
-+
-+        // Handle selection first.
-+        if (!args.right && (e.ctrlKey || e.metaKey)) {
-+            this.msgSelect(id, $H({ ctrl: true }).merge(args).toObject());
-+        } else if (e.shiftKey) {
-+            this.msgSelect(id, $H({ shift: true }).merge(args).toObject());
-+        } else if (this.isSelected('domid', id)) {
-+            if (!args.right && this.selectedCount()) {
-+                d.selectIfNoDrag = true;
-+            }
-+        } else {
-+            this.msgSelect(id, args);
-+        }
-+    }.bind(DimpBase),
-+    onEnd: function(d, e) {
-+        if (d.selectIfNoDrag && !d.wasDragged) {
-+            this.msgSelect(d.element.id, { right: e.isRightClick() });
-+        }
-+    }.bind(DimpBase)
-+};
-+
-+DimpBase._folderDragConfig = {
-+    ghosting: true,
-+    offset: { x: 5, y: 5 },
-+    scroll: 'normalfolders',
-+    threshold: 5,
-+    onDrag: function(d, e) {
-+        if (!d.wasDragged) {
-+            $('newfolder').hide();
-+            $('dropbase').show();
-+            d.ghost.removeClassName('on');
-+        }
-+    },
-+    onEnd: function(d, e) {
-+        if (d.wasDragged) {
-+            $('newfolder').show();
-+            $('dropbase').hide();
-+        }
-+    }
-+};
-+
-+DimpBase._folderDropConfig = {
-+    hoverclass: 'dragdrop',
-+    caption: function(drop, drag) {
-+        var d = drag.readAttribute('l'),
-+            ftype = drop.readAttribute('ftype'),
-+            l = drop.readAttribute('l'),
-+            m = DIMP.text.moveto;
-+        if (drop == $('dropbase')) {
-+            return m.replace(/%s/, d).replace(/%s/, DIMP.text.baselevel);
-+        } else if (drag.hasClassName('folder')) {
-+            return (ftype != 'special' && !this.isSubfolder(drag, drop)) ? m.replace(/%s/, d).replace(/%s/, l) : '';
-+        } else {
-+            return ftype != 'container' ? m.replace(/%s/, this._dragCaption()).replace(/%s/, l) : '';
-+        }
-+    }.bind(DimpBase),
-+    onDrop: DimpBase._folderDropHandler.bind(DimpBase)
-+};
-+
-+/* Stuff to do immediately when page is ready. */
-+document.observe('dom:loaded', function() {
-+    $('dimpLoading').hide();
-+    $('dimpPage').show();
-+
-+    /* Create the folder list. Any pending notifications will be caught via
-+     * the return from this call. */
-+    DimpCore.doAction('ListFolders', {}, [], DimpBase._folderLoadCallback.bind(DimpBase));
-+
-+    /* Start message list loading as soon as possible. */
-+    if (!DimpBase.delay_onload) {
-+        DimpBase._onLoad();
-+    }
-+
-+    /* Disable text selection in preview pane for IE 6. */
-+    if (DIMP.conf.is_ie6) {
-+        document.observe('selectstart', Event.stop);
-+    }
-+
-+    /* Remove unneeded search folders. */
-+    if (!DIMP.conf.search_all) {
-+        DimpBase.sfiltersfolder.unset('sf_all');
-+    }
-+
-+    /* Check for new mail. */
-+    DimpBase.setPollFolders();
-+
-+    /* Bind key shortcuts. */
-+    document.observe('keydown', DimpBase._keydownHandler.bind(DimpBase));
-+
-+    /* Resize elements on window size change. */
-+    Event.observe(window, 'resize', DimpBase._onResize.bind(DimpBase));
-+
-+    /* Since IE 6 doesn't support hover over non-links, use javascript events
-+     * to replicate mouseover CSS behavior. */
-+    if (DIMP.conf.is_ie6) {
-+        var links = [], tmp;
-+        if (tmp = $('dimpbarActions')) {
-+            links.push(tmp.select('SPAN'));
-+        }
-+        if (tmp = $('serviceActions')) {
-+            links.push(tmp.select('LI.servicelink'));
-+        }
-+        if (tmp = $('applicationfolders')) {
-+            links.push(tmp.select('UL LI'));
-+        }
-+        links.flatten().compact().each(function(e) {
-+            e.observe('mouseover', e.addClassName.curry('over')).observe('mouseout', e.removeClassName.curry('over'));
-+        });
-+    }
-+});
-+
-+/* Stuff to do after window is completely loaded. Don't init viewport until
-+ * now for non-Gecko/Opera browsers since sizing functions might not work
-+ * properly before. */
-+if (DimpBase.delay_onload) {
-+    Event.observe(window, 'load', DimpBase._onLoad.bind(DimpBase));
-+}
-+
-+/* Need to register a callback function for doAction to catch viewport
-+ * information returned from the server. */
-+DimpCore.onDoActionComplete = function(r) {
-+    if (DimpBase.viewport && r.response.viewport) {
-+        DimpBase.viewport.ajaxResponse(r.response.viewport);
-+    }
-+};
-+
-+/* Extend these functions from DimpCore since additional processing needs to
-+ * be done re: drag/drop and menu manipulation. */
-+DimpCore.addMouseEvents = DimpCore.addMouseEvents.wrap(DimpBase._addMouseEvents.bind(DimpBase));
-+DimpCore.removeMouseEvents = DimpCore.removeMouseEvents.wrap(DimpBase._removeMouseEvents.bind(DimpBase));
-diff --git a/js/src/DimpBase.js b/js/src/DimpBase.js
-index 9c1668e..96cd917 100644
---- a/js/src/DimpBase.js
-+++ b/js/src/DimpBase.js
-@@ -1545,7 +1545,7 @@ var DimpBase = {
- 
-         div = new Element('DIV', { className: ob.cl || 'base', id: fid + '_div' });
-         if (ob.i) {
--            div.update(ob.i);
-+            div.setStyle({ backgroundImage: 'url("' + ob.i + '")' });
-         }
-         if (ob.ch) {
-             div.writeAttribute({ className: 'exp' }).observe('mouseover', this.bcache.get('mo_folder') || this.bcache.set('mo_folder', function(e) {
-diff --git a/lib/DIMP.php b/lib/DIMP.php
-index 8518210..0aa3b78 100644
---- a/lib/DIMP.php
-+++ b/lib/DIMP.php
-@@ -414,8 +414,13 @@ class DIMP {
-         }
- 
-         if ($elt['user_icon']) {
--            $ob->cl = 'custom';
--            $ob->i = Horde::img($elt['icon'], $elt['alt'], '', $elt['icondir']);
-+            $ob->cl = 'customimg';
-+            $dir = empty($elt['icondir'])
-+                ? $GLOBALS['registry']->getImageDir()
-+                : $elt['icondir'];
-+            $ob->i = empty($dir)
-+                ? $elt['icon']
-+                : $dir . '/' . $elt['icon'];
-         }
- 
-         return $ob;
-diff --git a/themes/screen.css b/themes/screen.css
-index c33b148..cce11b3 100644
---- a/themes/screen.css
-+++ b/themes/screen.css
-@@ -464,7 +464,7 @@ div.msgSize img {
-     height: 100%;
-     background: transparent url("graphics/folder_create.png") center left no-repeat;
- }
--#sidebarPanel .drafts, #sidebarPanel .inbox, #sidebarPanel .sent, #sidebarPanel .spam, #sidebarPanel .trash {
-+#sidebarPanel .drafts, #sidebarPanel .inbox, #sidebarPanel .sent, #sidebarPanel .spam, #sidebarPanel .trash, #sidebarPanel .customimg {
-     display: inline;
-     float: left;
-     width: 20px;
--- 
-tg: (6938161..) t/dimp/H/MS/FixBrokenFolderImages (depends on: master)
--- 
-TOPGIT patch commit log
-=======================
-
-commit 12a42ba2183476ce329b567490ff5013727d8a39
-Author: Gunnar Wrobel <p at rdus.de>
-Date:   Sat Feb 7 23:54:51 2009 +0000
-
-    Fix the style name.
-
-commit 8588d2b184f6244655c219104b4d8119f0ea4644
-Author: Gunnar Wrobel <p at rdus.de>
-Date:   Sat Feb 7 18:43:00 2009 +0000
-
-     kolab/issue3328 ([Webclient] DIMP groupware folder names display bug)





More information about the commits mailing list