1 /* 2 * ***** BEGIN LICENSE BLOCK ***** 3 * Zimbra Collaboration Suite Web Client 4 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Synacor, Inc. 5 * 6 * The contents of this file are subject to the Common Public Attribution License Version 1.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at: https://www.zimbra.com/license 9 * The License is based on the Mozilla Public License Version 1.1 but Sections 14 and 15 10 * have been added to cover use of software over a computer network and provide for limited attribution 11 * for the Original Developer. In addition, Exhibit A has been modified to be consistent with Exhibit B. 12 * 13 * Software distributed under the License is distributed on an "AS IS" basis, 14 * WITHOUT WARRANTY OF ANY KIND, either express or implied. 15 * See the License for the specific language governing rights and limitations under the License. 16 * The Original Code is Zimbra Open Source Web Client. 17 * The Initial Developer of the Original Code is Zimbra, Inc. All rights to the Original Code were 18 * transferred by Zimbra, Inc. to Synacor, Inc. on September 14, 2015. 19 * 20 * All portions of the code are Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Synacor, Inc. All Rights Reserved. 21 * ***** END LICENSE BLOCK ***** 22 */ 23 24 /** 25 * Creates a mail item. 26 * @constructor 27 * @class 28 * This class represents a mail item, which may be a conversation or a mail 29 * message. 30 * 31 * @param {constant} type the type of object (conv or msg) 32 * @param {int} id the unique ID 33 * @param {ZmMailList} list the list that contains this mail item 34 * @param {Boolean} noCache if <code>true</code>, do not cache this item 35 * 36 * @extends ZmItem 37 */ 38 ZmMailItem = function(type, id, list, noCache) { 39 40 if (arguments.length == 0) { return; } 41 ZmItem.call(this, type, id, list, noCache); 42 43 this._loaded = false; 44 this._initializeParticipants(); 45 }; 46 47 ZmMailItem.prototype = new ZmItem; 48 ZmMailItem.prototype.constructor = ZmMailItem; 49 50 ZmMailItem.sortBy = ZmSearch.DATE_DESC; 51 ZmMailItem.sortCompare = 52 function(itemA, itemB) { 53 var sortBy = ZmMailItem.sortBy; 54 if (!sortBy || (sortBy != ZmSearch.DATE_DESC && sortBy != ZmSearch.DATE_ASC)) { return 0; } 55 56 var itemDateA = parseInt(itemA.date); 57 var itemDateB = parseInt(itemB.date); 58 if (sortBy == ZmSearch.DATE_DESC) { 59 return (itemDateA > itemDateB) ? -1 : (itemDateA < itemDateB) ? 1 : 0; 60 } 61 if (sortBy == ZmSearch.DATE_ASC) { 62 return (itemDateA > itemDateB) ? 1 : (itemDateA < itemDateB) ? -1 : 0; 63 } 64 }; 65 66 ZmMailItem.prototype.toString = 67 function() { 68 return "ZmMailItem"; 69 }; 70 71 /** 72 * Gets the read/unread icon. 73 * 74 * @return {String} the icon 75 */ 76 ZmMailItem.prototype.getReadIcon = 77 function() { 78 return this.isUnread ? "MsgUnread" : "MsgRead"; 79 }; 80 81 /** 82 * Gets the mute/unmute icon. 83 * 84 * @return {String} the icon 85 */ 86 ZmMailItem.prototype.getMuteIcon = 87 function() { 88 return ""; 89 }; 90 91 92 ZmMailItem.prototype.getColor = 93 function() { 94 if (!this.tags || this.tags.length !== 1) { 95 return null; 96 } 97 var tagList = appCtxt.getAccountTagList(this); 98 99 var tag = tagList.getByNameOrRemote(this.tags[0]); 100 101 return tag.getColor(); 102 }; 103 104 /** 105 * Clears this item. 106 * 107 */ 108 ZmMailItem.prototype.clear = function() { 109 110 // only clear data if no more views are using this item 111 if (this.refCount <= 1) { 112 this._clearParticipants(); 113 this._loaded = false; 114 } 115 116 ZmItem.prototype.clear.call(this); 117 }; 118 119 ZmMailItem.prototype.getFolderId = 120 function() { 121 return this.folderId; 122 }; 123 124 ZmMailItem.prototype.notifyModify = 125 function(obj, batchMode) { 126 var fields = {}; 127 if (obj.e && obj.e.length) { 128 this._clearParticipants(); 129 this._initializeParticipants(); 130 for (var i = 0; i < obj.e.length; i++) { 131 this._parseParticipantNode(obj.e[i]); 132 } 133 fields[ZmItem.F_FROM] = true; 134 this._notify(ZmEvent.E_MODIFY, {fields:fields}); 135 } 136 137 return ZmItem.prototype.notifyModify.apply(this, arguments); 138 }; 139 140 ZmMailItem.prototype._initializeParticipants = 141 function() { 142 this.participants = new AjxVector(); 143 this.participantsElided = false; 144 }; 145 146 ZmMailItem.prototype._clearParticipants = 147 function() { 148 if (this.participants) { 149 this.participants.removeAll(); 150 this.participants = null; 151 this.participantsElided = false; 152 } 153 }; 154 155 ZmMailItem.prototype._getFlags = 156 function() { 157 var list = ZmItem.prototype._getFlags.call(this); 158 list.push(ZmItem.FLAG_UNREAD, ZmItem.FLAG_MUTE, ZmItem.FLAG_REPLIED, ZmItem.FLAG_FORWARDED, ZmItem.FLAG_READ_RECEIPT_SENT, ZmItem.FLAG_PRIORITY); 159 return list; 160 }; 161 162 ZmMailItem.prototype._markReadLocal = 163 function(on) { 164 this.isUnread = !on; 165 this._notify(ZmEvent.E_FLAGS, {flags:[ZmItem.FLAG_UNREAD]}); 166 }; 167 168 ZmMailItem.prototype._parseParticipantNode = 169 function(node) { 170 var type = AjxEmailAddress.fromSoapType[node.t]; 171 if (type == AjxEmailAddress.READ_RECEIPT) { 172 this.readReceiptRequested = true; 173 } else { 174 // if we can find the person in contacts, use the name from there 175 var contactList = AjxDispatcher.run("GetContacts"), 176 contact = contactList && contactList.getContactByEmail(node.a), 177 fullName = contact && contact.getFullNameForDisplay(false); 178 179 var addr = new AjxEmailAddress(node.a, type, fullName || node.p, node.d, node.isGroup, node.isGroup && node.exp); 180 var ac = window.parentAppCtxt || window.appCtxt; 181 ac.setIsExpandableDL(node.a, addr.canExpand); 182 this.participants.add(addr); 183 } 184 }; 185 186 /** 187 * Gets the email addresses of the participants. 188 * 189 * @return {Array} an array of email addresses 190 */ 191 ZmMailItem.prototype.getEmails = 192 function() { 193 return this.participants.map("address"); 194 }; 195 196 /** 197 * Checks if this item is in Junk or Trash and the user is not including 198 * those in search results. 199 * 200 * @return {Boolean} <code>true</code> if this item is in the Junk or Trash folder 201 */ 202 ZmMailItem.prototype.ignoreJunkTrash = 203 function() { 204 return Boolean((this.folderId == ZmFolder.ID_SPAM && !appCtxt.get(ZmSetting.SEARCH_INCLUDES_SPAM)) || 205 (this.folderId == ZmFolder.ID_TRASH && !appCtxt.get(ZmSetting.SEARCH_INCLUDES_TRASH))); 206 }; 207 208 ZmMailItem.prototype.setAutoSendTime = 209 function(autoSendTime) { 210 var wasScheduled = this.isScheduled; 211 var isDate = AjxUtil.isDate(autoSendTime); 212 this.flagLocal(ZmItem.FLAG_ISSCHEDULED, isDate); 213 var autoSendTime = isDate ? autoSendTime : null; 214 if (autoSendTime != this.autoSendTime) { 215 this.autoSendTime = autoSendTime; 216 this._notify(ZmEvent.E_MODIFY); 217 } 218 if (wasScheduled != this.isScheduled) { 219 this._notify(ZmEvent.E_FLAGS, {flags: ZmItem.FLAG_ISSCHEDULED}); 220 } 221 }; 222