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