1 /*
  2  * ***** BEGIN LICENSE BLOCK *****
  3  * Zimbra Collaboration Suite Web Client
  4  * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 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) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2016 Synacor, Inc. All Rights Reserved.
 21  * ***** END LICENSE BLOCK *****
 22  */
 23 
 24 /**
 25  * @overview
 26  * This file contains a share class.
 27  */
 28 
 29 /**
 30  * Creates a share with the given information about the sharer, the sharee, and
 31  * what is being shared.
 32  * @class
 33  * A share comprises information about an object that is shared by one user with
 34  * another user. Currently, only organizers may be shared.
 35  * <br/>
 36  * <br/>
 37  * XML representation:
 38  * <pre>
 39  * <!ELEMENT share (grantee,grantor,link)>
 40  * <!ATTLIST share xmlns CDATA #FIXED "urn:zimbraShare">
 41  * <!ATTLIST share version NMTOKEN #FIXED "0.1">
 42  * <!ATTLIST share action (new|edit|delete|accept|decline) #REQUIRED>
 43  *
 44  * <!ELEMENT grantee EMPTY>
 45  * <!ATTLIST grantee id CDATA #REQUIRED>
 46  * <!ATTLIST grantee name CDATA #REQUIRED>
 47  * <!ATTLIST grantee email CDATA #REQUIRED>
 48  *
 49  * <!ELEMENT grantor EMPTY>
 50  * <!ATTLIST grantor id CDATA #REQUIRED>
 51  * <!ATTLIST grantor name CDATA #REQUIRED>
 52  * <!ATTLIST grantor email CDATA #REQUIRED>
 53  *
 54  * <!ELEMENT link EMPTY>
 55  * <!ATTLIST link id NMTOKEN #REQUIRED>
 56  * <!ATTLIST link name CDATA #REQUIRED>
 57  * <!ATTLIST link view (appointment|...) #REQUIRED>
 58  * <!ATTLISt link perm CDATA #REQUIRED>
 59  * </pre>
 60  *
 61  * @author Andy Clark
 62  * 
 63  * @param	{Hash}	params		a hash of parameters
 64  * @param {Object}	params.object		the object being shared
 65  * @param {constant}	params.granteeType	the grantee type (see <code>ZmShare.TYPE_</code> constants) (everyone, or a single user)
 66  * @param {String}	params.granteeId		a unique ID for the grantee
 67  * @param {String}	params.granteeName	the grantee's name
 68  * @param {String}	granteePwd			the grantee's password
 69  * @param {constant}	params.perm		the grantee's permissions on the shared object
 70  * @param {Boolean}	params.inherit		if <code>true</code>, children inherit share info
 71  * @param {Boolean}	params.invalid		if <code>true</code>, the share is invalid
 72  */
 73 ZmShare = function(params) {
 74 
 75 	this.grantee = {};
 76 	this.grantor = {};
 77 	this.link = {};
 78 
 79 	if (!params) { return; }
 80 	this.object = params.object;
 81 	this.grantee.type = params.granteeType;
 82 	this.grantee.id = params.granteeId;
 83 	this.grantee.name = params.granteeName || "";
 84 	this.link.inh = params.inherit;
 85 	this.link.pw = params.granteePwd;
 86 	this.invalid = params.invalid;
 87 	this.setPermissions(params.perm);
 88 };
 89 
 90 // Constants
 91 
 92 ZmShare.URI = "urn:zimbraShare";
 93 ZmShare.VERSION = "0.2";
 94 ZmShare.PREV_VERSION = "0.1"; // keep this till it's no longer supported
 95 
 96 // actions
 97 /**
 98  * Defines the "new" action.
 99  * 
100  * @type {String}
101  */
102 ZmShare.NEW		= "new";
103 /**
104  * Defines the "edit" action.
105  * 
106  * @type {String}
107  */
108 ZmShare.EDIT	= "edit";
109 /**
110  * Defines the "delete" action.
111  * 
112  * @type {String}
113  */
114 ZmShare.DELETE	= "delete";
115 /**
116  * Defines the "accept" action.
117  * 
118  * @type {String}
119  */
120 ZmShare.ACCEPT	= "accept";
121 /**
122  * Defines the "decline" action.
123  * 
124  * @type {String}
125  */
126 ZmShare.DECLINE	= "decline";
127 /**
128  * Defines the "notify" action.
129  * 
130  * @type {String}
131  */
132 ZmShare.NOTIFY  = "notify";
133 /**
134  * Defines the "resend" action.
135  * 
136  * @type {String}
137  */
138 ZmShare.RESEND	= "resend";
139 /**
140  * Defines the "revoke" action.
141  * 
142  * @type {String}
143  */
144 ZmShare.REVOKE	= "revoke";
145 
146 ZmShare.ACTION_LABEL = {};
147 ZmShare.ACTION_LABEL[ZmShare.EDIT]		= ZmMsg.edit;
148 ZmShare.ACTION_LABEL[ZmShare.RESEND]	= ZmMsg.resend;
149 ZmShare.ACTION_LABEL[ZmShare.REVOKE]	= ZmMsg.revoke;
150 
151 // allowed permission bits
152 /**
153  * Defines the "read" allowed permission.
154  */
155 ZmShare.PERM_READ		= "r";
156 /**
157  * Defines the "write" allowed permission.
158  */
159 ZmShare.PERM_WRITE		= "w";
160 /**
161  * Defines the "insert" allowed permission.
162  */
163 ZmShare.PERM_INSERT		= "i";
164 /**
165  * Defines the "delete" allowed permission.
166  */
167 ZmShare.PERM_DELETE		= "d";
168 /**
169  * Defines the "admin" allowed permission.
170  */
171 ZmShare.PERM_ADMIN		= "a";
172 /**
173  * Defines the "workflow" allowed permission.
174  */
175 ZmShare.PERM_WORKFLOW	= "x";
176 /**
177  * Defines the "private" allowed permission.
178  */
179 ZmShare.PERM_PRIVATE	= "p";
180 
181 // virtual permissions
182 ZmShare.PERM_CREATE_SUBDIR	= "c";
183 
184 // restricted permission bits
185 /**
186  * Defines the "no read" restricted permission.
187  */
188 ZmShare.PERM_NOREAD		= "-r";
189 /**
190  * Defines the "no write" restricted permission.
191  */
192 ZmShare.PERM_NOWRITE	= "-w";
193 /**
194  * Defines the "no insert" restricted permission.
195  */
196 ZmShare.PERM_NOINSERT	= "-i";
197 /**
198  * Defines the "no delete" restricted permission.
199  */
200 ZmShare.PERM_NODELETE	= "-d";
201 /**
202  * Defines the "no admin" restricted permission.
203  */
204 ZmShare.PERM_NOADMIN	= "-a";
205 /**
206  * Defines the "no workflow" restricted permission.
207  */
208 ZmShare.PERM_NOWORKFLOW	= "-x";
209 
210 // allowed permission names
211 ZmShare.PERMS = {};
212 ZmShare.PERMS[ZmShare.PERM_READ]		= ZmMsg.shareActionRead;
213 ZmShare.PERMS[ZmShare.PERM_WRITE]		= ZmMsg.shareActionWrite;
214 ZmShare.PERMS[ZmShare.PERM_INSERT]		= ZmMsg.shareActionInsert;
215 ZmShare.PERMS[ZmShare.PERM_DELETE]		= ZmMsg.shareActionDelete;
216 ZmShare.PERMS[ZmShare.PERM_ADMIN]		= ZmMsg.shareActionAdmin;
217 ZmShare.PERMS[ZmShare.PERM_WORKFLOW]	= ZmMsg.shareActionWorkflow;
218 
219 // restricted permission names
220 ZmShare.PERMS[ZmShare.PERM_NOREAD]		= ZmMsg.shareActionNoRead;
221 ZmShare.PERMS[ZmShare.PERM_NOWRITE]		= ZmMsg.shareActionNoWrite;
222 ZmShare.PERMS[ZmShare.PERM_NOINSERT]	= ZmMsg.shareActionNoInsert;
223 ZmShare.PERMS[ZmShare.PERM_NODELETE]	= ZmMsg.shareActionNoDelete;
224 ZmShare.PERMS[ZmShare.PERM_NOADMIN]		= ZmMsg.shareActionNoAdmin;
225 ZmShare.PERMS[ZmShare.PERM_NOWORKFLOW]	= ZmMsg.shareActionNoWorkflow;
226 
227 // role permissions
228 /**
229  * Defines the "none" role.
230  * 
231  * @type {String}
232  */
233 ZmShare.ROLE_NONE		= "NONE";
234 /**
235  * Defines the "viewer" role.
236  * 
237  * @type {String}
238  */
239 ZmShare.ROLE_VIEWER		= "VIEWER";
240 /**
241  * Defines the "manager" role.
242  * 
243  * @type {String}
244  */
245 ZmShare.ROLE_MANAGER	= "MANAGER";
246 /**
247  * Defines the "admin" role.
248  * 
249  * @type {String}
250  */
251 ZmShare.ROLE_ADMIN		= "ADMIN";
252 
253 // role names
254 ZmShare.ROLE_TEXT = {};
255 ZmShare.ROLE_TEXT[ZmShare.ROLE_NONE]	= ZmMsg.shareRoleNone;
256 ZmShare.ROLE_TEXT[ZmShare.ROLE_VIEWER]	= ZmMsg.shareRoleViewer;
257 ZmShare.ROLE_TEXT[ZmShare.ROLE_MANAGER]	= ZmMsg.shareRoleManager;
258 ZmShare.ROLE_TEXT[ZmShare.ROLE_ADMIN]	= ZmMsg.shareRoleAdmin;
259 
260 ZmShare.ROLE_PERMS = {};
261 ZmShare.ROLE_PERMS[ZmShare.ROLE_NONE]		= "";
262 ZmShare.ROLE_PERMS[ZmShare.ROLE_VIEWER]		= "r";
263 ZmShare.ROLE_PERMS[ZmShare.ROLE_MANAGER]	= "rwidx";
264 ZmShare.ROLE_PERMS[ZmShare.ROLE_ADMIN]		= "rwidxa";
265 
266 /**
267  * Defines the "all" type.
268  * 
269  * @type {String}
270  */
271 ZmShare.TYPE_ALL	= "all";
272 /**
273  * Defines the "user" type.
274  * 
275  * @type {String}
276  */
277 ZmShare.TYPE_USER	= "usr";
278 /**
279  * Defines the "group" type.
280  * 
281  * @type {String}
282  */
283 ZmShare.TYPE_GROUP	= "grp";
284 /**
285  * Defines the "domain" type.
286  * 
287  * @type {String}
288  */
289 ZmShare.TYPE_DOMAIN	= "dom";
290 /**
291  * Defines the "COS" type.
292  * 
293  * @type {String}
294  */
295 ZmShare.TYPE_COS	= "cos";
296 /**
297  * Defines the "guest" type.
298  * 
299  * @type {String}
300  */
301 ZmShare.TYPE_GUEST	= "guest";
302 /**
303  * Defines the "public" type.
304  * 
305  * @type {String}
306  */
307 ZmShare.TYPE_PUBLIC	= "pub";
308 
309 ZmShare.ZID_ALL = "00000000-0000-0000-0000-000000000000";
310 ZmShare.ZID_PUBLIC = "99999999-9999-9999-9999-999999999999";
311 
312 ZmShare.SHARE = "SHARE";
313 ZmShare.GRANT = "GRANT";
314 
315 // message subjects
316 ZmShare._SUBJECTS = {};
317 ZmShare._SUBJECTS[ZmShare.NEW] = ZmMsg.shareCreatedSubject;
318 ZmShare._SUBJECTS[ZmShare.EDIT] = ZmMsg.shareModifiedSubject;
319 ZmShare._SUBJECTS[ZmShare.DELETE] = ZmMsg.shareRevokedSubject;
320 ZmShare._SUBJECTS[ZmShare.ACCEPT] = ZmMsg.shareAcceptedSubject;
321 ZmShare._SUBJECTS[ZmShare.DECLINE] = ZmMsg.shareDeclinedSubject;
322 ZmShare._SUBJECTS[ZmShare.NOTIFY]  = ZmMsg.shareNotifySubject;
323 
324 // formatters
325 ZmShare._TEXT = null;
326 ZmShare._HTML = null;
327 ZmShare._HTML_NOTE = null;
328 ZmShare._XML = null;
329 
330 // Utility methods
331 
332 ZmShare.getDefaultMountpointName = function(owner, name) {
333     if (!ZmShare._defaultNameFormatter) {
334         ZmShare._defaultNameFormatter = new AjxMessageFormat(ZmMsg.shareNameDefault);
335     }
336     var defaultName = ZmShare._defaultNameFormatter.format([owner, name]);
337 	return defaultName.replace(/\//g," ");
338 };
339 
340 /**
341  * Gets the role name.
342  * 
343  * @param	{constant}	role		the role (see <code>ZmShare.ROLE_</code> constants)
344  * @return	{String}	the name
345  */
346 ZmShare.getRoleName =
347 function(role) {
348 	return ZmShare.ROLE_TEXT[role] || ZmMsg.shareRoleCustom;
349 };
350 
351 /**
352  * Gets the role actions.
353  * 
354  * @param	{constant}	role		the role (see <code>ZmShare.ROLE_</code> constants)
355  * @return	{String}	the actions
356  */
357 ZmShare.getRoleActions =
358 function(role) {
359 	var perm = ZmShare.ROLE_PERMS[role];
360 	var actions = [];
361 	if (perm) {
362 		for (var i = 0; i < perm.length; i++) {
363 			var c = perm.charAt(i);
364 			if(c == 'x') continue;
365             if (c == "-") {
366 				c += perm.charAt(++i);
367 			}
368 			actions.push(ZmShare.PERMS[c]);
369 		}
370 	}
371 	return (actions.length > 0) ? actions.join(", ") : ZmMsg.shareActionNone;
372 };
373 
374 // role action names
375 ZmShare.ACTIONS = {};
376 ZmShare.ACTIONS[ZmShare.ROLE_NONE]		= ZmShare.getRoleActions(ZmShare.ROLE_NONE);
377 ZmShare.ACTIONS[ZmShare.ROLE_VIEWER]	= ZmShare.getRoleActions(ZmShare.ROLE_VIEWER);
378 ZmShare.ACTIONS[ZmShare.ROLE_MANAGER]	= ZmShare.getRoleActions(ZmShare.ROLE_MANAGER);
379 ZmShare.ACTIONS[ZmShare.ROLE_ADMIN]		= ZmShare.getRoleActions(ZmShare.ROLE_ADMIN);
380 
381 // Static methods
382 
383 /**
384  * Creates the share from the DOM.
385  * 
386  * @param	{Object}	doc		the document
387  * @return	{ZmShare}	the resulting share
388  */
389 ZmShare.createFromDom =
390 function(doc) {
391 	// NOTE: This code initializes share info from the Zimbra share format, v0.1
392 	var share = new ZmShare();
393 
394 	var shareNode = doc.documentElement;
395 	share.version = shareNode.getAttribute("version");
396 	if (share.version != ZmShare.VERSION && share.version != ZmShare.PREV_VERSION) { //support previous version here for smooth transition. 
397 		throw "Zimbra share version must be " + ZmShare.VERSION;
398 	}
399 	share.action = shareNode.getAttribute("action");
400 	
401 	// NOTE: IE's getElementsByTagName doesn't seem to return the specified
402 	//		 tags when they're in a namespace. Will have to do this the
403 	//		 old-fashioned way because I'm tired of fighting with it...
404 	var child = shareNode.firstChild;
405 	while (child != null) {
406 		switch (child.nodeName) {
407 			case "grantee": case "grantor": {
408 				share[child.nodeName].id = child.getAttribute("id");
409 				share[child.nodeName].email = child.getAttribute("email");
410 				share[child.nodeName].name = child.getAttribute("name");
411 				break;
412 			}
413 			case "link": {
414 				share.link.id = child.getAttribute("id");
415 				share.link.name = child.getAttribute("name");
416 				share.link.view = child.getAttribute("view");
417 				share.link.perm = child.getAttribute("perm");
418 				break;
419 			}
420 		}
421 		child = child.nextSibling;
422 	}
423 
424 	return share;
425 };
426 
427 // Public methods
428 
429 /**
430  * Returns a string representation of the object.
431  * 
432  * @return		{String}		a string representation of the object
433  */
434 ZmShare.prototype.toString =
435 function() {
436 	return "ZmShare";
437 };
438 
439 /**
440  * Sets the permission.
441  * 
442  * @param	{constant}	perm		the permission (see <code>ZmShare.PERM_</code> constants)
443  */
444 ZmShare.prototype.setPermissions =
445 function(perm) {
446 	this.link.perm = perm;
447 	this.link.role = ZmShare.getRoleFromPerm(perm);
448 };
449 
450 /**
451  * Checks if the given permission exists on this share.
452  * 
453  * @param	{constant}	perm		the permission (see <code>ZmShare.PERM_</code> constants)
454  * @return	{Boolean}	<code>true</code> if the permission is allowed on this share
455  */
456 ZmShare.prototype.isPermAllowed =
457 function(perm) {
458 	if (this.link.perm) {
459 		var positivePerms = this.link.perm.replace(/-./g, "");
460 		return (positivePerms.indexOf(perm) != -1);
461 	}
462 	return false;
463 };
464 
465 /**
466  * Checks if the given permission is restricted for this share.
467  *
468  * @param	{constant}	perm		the permission (see <code>ZmShare.PERM_</code> constants)
469  * @return	{Boolean}	<code>true</code> if the permission is restricted on this share
470  */
471 ZmShare.prototype.isPermRestricted =
472 function(perm) {
473 	if (this.link.perm) {
474 		return (this.link.perm.indexOf("-" + perm) != -1);
475 	}
476 	return false;
477 };
478 
479 // Methods that return whether a particular permission exists on this share
480 /**
481  * Checks if the read permission exists on this share.
482  * 
483  * @return	{Boolean}	<code>true</code> if the read permission is allowed on this share
484  * @see ZmShare.PERM_READ
485  */
486 ZmShare.prototype.isRead = function() { return this.isPermAllowed(ZmShare.PERM_READ); };
487 /**
488  * Checks if the write permission exists on this share.
489  * 
490  * @return	{Boolean}	<code>true</code> if the write permission is allowed on this share
491  * @see ZmShare.PERM_WRITE
492  */
493 ZmShare.prototype.isWrite = function() { return this.isPermAllowed(ZmShare.PERM_WRITE); };
494 /**
495  * Checks if the insert permission exists on this share.
496  * 
497  * @return	{Boolean}	<code>true</code> if the insert permission is allowed on this share
498  * @see ZmShare.PERM_INSERT
499  */
500 ZmShare.prototype.isInsert = function() { return this.isPermAllowed(ZmShare.PERM_INSERT); };
501 /**
502  * Checks if the delete permission exists on this share.
503  * 
504  * @return	{Boolean}	<code>true</code> if the delete permission is allowed on this share
505  * @see ZmShare.PERM_DELETE
506  */
507 ZmShare.prototype.isDelete = function() { return this.isPermAllowed(ZmShare.PERM_DELETE); };
508 /**
509  * Checks if the admin permission exists on this share.
510  * 
511  * @return	{Boolean}	<code>true</code> if the admin permission is allowed on this share
512  * @see ZmShare.PERM_ADMIN
513  */
514 ZmShare.prototype.isAdmin = function() { return this.isPermAllowed(ZmShare.PERM_ADMIN); };
515 /**
516  * Checks if the workflow permission exists on this share.
517  * 
518  * @return	{Boolean}	<code>true</code> if the workflow permission is allowed on this share
519  * @see ZmShare.PERM_WORKFLOW
520  */
521 ZmShare.prototype.isWorkflow = function() { return this.isPermAllowed(ZmShare.PERM_WORKFLOW); };
522 /**
523  * Checks if the private permission exists on this share.
524  * 
525  * @return	{Boolean}	<code>true</code> if the private permission is allowed on this share
526  * @see ZmShare.PERM_PRIVATE
527  */
528 ZmShare.prototype.hasPrivateAccess = function() { return this.isPermAllowed(ZmShare.PERM_PRIVATE); };
529 
530 // Protected static methods
531 
532 /**
533  * @private
534  */
535 ZmShare._getFolderType =
536 function(view) {
537 	var folderKey = (view && ZmOrganizer.FOLDER_KEY[ZmOrganizer.TYPE[view]]) || "folder";
538 	return ZmMsg[folderKey];
539 };
540 
541 
542 // Static methods
543 
544 /**
545  * Creates the share from JS.
546  * 
547  * @param	
548  * @return	{ZmShare}	the resulting share
549  */
550 ZmShare.createFromJs =
551 function(parent, grant) {
552 	return new ZmShare({object:parent, granteeType:grant.gt, granteeId:grant.zid,
553 						granteeName:grant.d, perm:grant.perm, inherit:grant.inh,
554 						granteePwd:grant.pw, invalid:grant.invalid});
555 };
556 
557 // Public methods
558 /**
559  * Checks if the grantee type is "all".
560  * 
561  * @return	{Boolean}	<code>true</code> if type "all"
562  * @see		ZmShare.TYPE_ALL
563  */
564 ZmShare.prototype.isAll =
565 function() {
566 	return this.grantee.type == ZmShare.TYPE_ALL;
567 };
568 /**
569  * Checks if the grantee type is "user".
570  * 
571  * @return	{Boolean}	<code>true</code> if type "user"
572  * @see		ZmShare.TYPE_USER
573  */
574 ZmShare.prototype.isUser =
575 function() {
576 	return this.grantee.type == ZmShare.TYPE_USER;
577 };
578 /**
579  * Checks if the grantee type is "group".
580  * 
581  * @return	{Boolean}	<code>true</code> if type "group"
582  * @see		ZmShare.TYPE_GROUP
583  */
584 ZmShare.prototype.isGroup =
585 function() {
586 	return this.grantee.type == ZmShare.TYPE_GROUP;
587 };
588 /**
589  * Checks if the grantee type is "domain".
590  * 
591  * @return	{Boolean}	<code>true</code> if type "domain"
592  * @see		ZmShare.TYPE_DOMAIN
593  */
594 ZmShare.prototype.isDomain =
595 function() {
596 	return this.grantee.type == ZmShare.TYPE_DOMAIN;
597 };
598 /**
599  * Checks if the grantee type is "guest".
600  * 
601  * @return	{Boolean}	<code>true</code> if type "guest"
602  * @see		ZmShare.TYPE_GUEST
603  */
604 ZmShare.prototype.isGuest =
605 function() {
606 	return this.grantee.type == ZmShare.TYPE_GUEST;
607 };
608 /**
609  * Checks if the grantee type is "public".
610  * 
611  * @return	{Boolean}	<code>true</code> if type "public"
612  * @see		ZmShare.TYPE_PUBLIC
613  */
614 ZmShare.prototype.isPublic =
615 function() {
616 	return (this.grantee.type == ZmShare.TYPE_PUBLIC);
617 };
618 
619 /**
620  * Grants the permission.
621  * 
622  * @param	{constant}	perm	the permission (see <code>ZmShare.PERM_</code> constants)
623  * @param	{String}	pw		
624  * @param	{constant}	replyType		ZmShareReply.NONE, ZmShareReply.STANDARD or ZmShareReply.QUICK
625  * @param	{constant}	shareAction		the share action, e.g. ZmShare.NEW or ZmShare.EDIT
626  * @param	{ZmBatchCommand}	batchCmd	the batch command
627  */
628 ZmShare.prototype.grant =
629 function(perm, pw, notes, replyType, shareAction, batchCmd) {
630 	this.link.perm = perm;
631 	var respCallback = new AjxCallback(this, this._handleResponseGrant, [notes, replyType, shareAction]);
632 	this._shareAction("grant", null, {perm: perm, pw: pw}, respCallback, batchCmd, notes);
633 };
634 
635 /**
636  * @private
637  */
638 ZmShare.prototype._handleResponseGrant =
639 function(notes, replyType, shareAction, result) {
640 	var action = result.getResponse().FolderActionResponse.action;
641 	this.grantee.id = action.zid;
642 	this.grantee.email = action.d;
643     if(replyType != ZmShareReply.NONE && action.d && action.zid) {
644         this._sendShareNotification(this.grantee.email, action.id,
645 		                            notes, shareAction);
646     }
647 };
648 
649 /**
650  * @private
651  */
652 ZmShare.prototype._sendShareNotification =
653 function(userEmail, folderId, notes, action, callback) {
654     var soapDoc = AjxSoapDoc.create("SendShareNotificationRequest", "urn:zimbraMail");
655     if (action != ZmShare.NEW)
656         soapDoc.setMethodAttribute("action", action);
657     var itemNode = soapDoc.set("item");
658     itemNode.setAttribute("id", folderId);
659     var emailNode = soapDoc.set("e");
660     emailNode.setAttribute("a",userEmail);
661     soapDoc.set("notes", notes);
662     appCtxt.getAppController().sendRequest({soapDoc: soapDoc, asyncMode: true, callback: callback});
663 };
664 
665 /**
666  * Revokes the share.
667  * 
668  * @param	{AjxCallback}	callback	the callback
669  */
670 ZmShare.prototype.revoke = 
671 function(callback) {
672 	var isAllShare = this.grantee && (this.grantee.type == ZmShare.TYPE_ALL);
673 	var actionAttrs = { zid: this.isPublic() ? ZmShare.ZID_PUBLIC : isAllShare ? ZmShare.ZID_ALL : this.grantee.id };
674 	var respCallback = new AjxCallback(this, this._handleResponseRevoke, [callback]);
675 	this._shareAction("!grant", actionAttrs, null, respCallback);
676 };
677 
678 /**
679  * Revokes multiple shares.
680  * 
681  * @param	{AjxCallback}	callback	the callback
682  * @param	{Object}	args		not used
683  * @param	{ZmBatchCommand}	batchCmd	the batch command
684  */
685 ZmShare.prototype.revokeMultiple =
686 function(callback, args, batchCmd) {
687 	var actionAttrs = { zid: this.isPublic() ? ZmShare.ZID_PUBLIC : this.grantee.id };
688 	var respCallback = new AjxCallback(this, this._handleResponseRevoke, [callback]);
689 	this._shareAction("!grant", actionAttrs, null, respCallback, batchCmd);
690 };
691 
692 /**
693  * @private
694  */
695 ZmShare.prototype._handleResponseRevoke =
696 function(callback) {
697 	if (callback) {
698 		callback.run();
699 	}
700 };
701 
702 /**
703  * Accepts the share.
704  * 
705  */
706 ZmShare.prototype.accept = 
707 function(name, color, replyType, notes, callback, owner) {
708 	var respCallback = new AjxCallback(this, this._handleResponseAccept, [replyType, notes, callback, owner]);
709 	var params = {
710 		l: ZmOrganizer.ID_ROOT,
711 		name: name,
712 		zid: this.grantor.id,
713 		rid: ZmOrganizer.normalizeId(this.link.id),
714 		view: this.link.view
715 	};
716 	if (color) {
717 		params.color = color;
718 	}
719 
720 	if (String(color).match(/^#/)) {
721 		params.rgb = color;
722 		delete params.color;
723 	}
724 
725 	if (appCtxt.get(ZmSetting.CALENDAR_ENABLED) && ZmOrganizer.VIEW_HASH[ZmOrganizer.CALENDAR][this.link.view]) {
726 		params.f = ZmOrganizer.FLAG_CHECKED;
727 	}
728 	ZmMountpoint.create(params, respCallback);
729 };
730 
731 /**
732  * @private
733  */
734 ZmShare.prototype._handleResponseAccept =
735 function(replyType, notes, callback, owner) {
736 
737 	this.notes = notes;
738 
739 	if (callback) {
740 		callback.run();
741 	}
742 
743 	// check if we need to send message
744 	if (replyType != ZmShareReply.NONE) {
745 		this.sendMessage(ZmShare.ACCEPT, null, owner);
746 	}
747 };
748 
749 /**
750  * Sends a message.
751  * 
752  * @param	{constant}			mode		the request mode
753  * @param	{AjxVector}			addrs		a vector of {@link AjxEmailAddress} objects or <code>null</code> to send to the grantee
754  * @param	{String}			owner		the message owner
755  * @param	{ZmBatchCommand}	batchCmd	batchCommand to put the SendMsgRequest into or <code>null</code> to send the message immediately
756  */
757 ZmShare.prototype.sendMessage =
758 function(mode, addrs, owner, batchCmd) {
759 	// generate message
760 	if (!addrs) {
761 		var email = this.grantee.email;
762 		addrs = new AjxVector();
763 		addrs.add(new AjxEmailAddress(email, AjxEmailAddress.TO));
764 	}
765 	var msg = this._createMsg(mode, addrs, owner);
766 	var accountName = appCtxt.multiAccounts ? (this.object ? (this.object.getAccount().name) : null ) : null;
767 
768 	// send message
769 	msg.send(false, null, null, accountName, false, false, batchCmd);
770 };
771 
772 
773 // Protected methods
774 
775 /**
776  * text formatters
777  * 
778  * @private
779  */
780 ZmShare._getText =
781 function(mode) {
782 	if (!ZmShare._TEXT) {
783 		ZmShare._TEXT = {};
784 		ZmShare._TEXT[ZmShare.NEW] = new AjxMessageFormat(ZmMsg.shareCreatedText);
785 		ZmShare._TEXT[ZmShare.EDIT] = new AjxMessageFormat(ZmMsg.shareModifiedText);
786 		ZmShare._TEXT[ZmShare.DELETE] = new AjxMessageFormat(ZmMsg.shareRevokedText);
787 		ZmShare._TEXT[ZmShare.ACCEPT] = new AjxMessageFormat(ZmMsg.shareAcceptedText);
788 		ZmShare._TEXT[ZmShare.DECLINE] = new AjxMessageFormat(ZmMsg.shareDeclinedText);
789 		ZmShare._TEXT[ZmShare.NOTIFY] = new AjxMessageFormat(ZmMsg.shareNotifyText);
790 	}
791 	return ZmShare._TEXT[mode];
792 };
793 	
794 /**
795  * html formatters
796  * 
797  * @private
798  */
799 ZmShare._getHtml =
800 function(mode) {
801 	if (!ZmShare._HTML) {
802 		ZmShare._HTML = {};
803 		ZmShare._HTML[ZmShare.NEW] = new AjxMessageFormat(ZmMsg.shareCreatedHtml);
804 		ZmShare._HTML[ZmShare.EDIT] = new AjxMessageFormat(ZmMsg.shareModifiedHtml);
805 		ZmShare._HTML[ZmShare.DELETE] = new AjxMessageFormat(ZmMsg.shareRevokedHtml);
806 		ZmShare._HTML[ZmShare.ACCEPT] = new AjxMessageFormat(ZmMsg.shareAcceptedHtml);
807 		ZmShare._HTML[ZmShare.DECLINE] = new AjxMessageFormat(ZmMsg.shareDeclinedHtml);
808 		ZmShare._HTML[ZmShare.NOTIFY] = new AjxMessageFormat(ZmMsg.shareNotifyHtml);
809 	}
810 	return ZmShare._HTML[mode];
811 };
812 
813 /**
814  * @private
815  */
816 ZmShare._getHtmlNote =
817 function() {
818 	if (!ZmShare._HTML_NOTE) {
819 		ZmShare._HTML_NOTE = new AjxMessageFormat(ZmMsg.shareNotesHtml);
820 	}
821 	return ZmShare._HTML_NOTE;
822 };
823 
824 /**
825  * xml formatter
826  * 
827  * @private
828  */
829 ZmShare._getXml =
830 function() {
831 	if (!ZmShare._XML) {
832 		var pattern = [
833 			'<share xmlns="{0}" version="{1}" action="{2}" >',
834 			'  <grantee id="{3}" email="{4}" name="{5}" />',
835 			'  <grantor id="{6}" email="{7}" name="{8}" />',
836 			'  <link id="{9}" name="{10}" view="{11}" perm="{12}" />',
837 			'  <notes>{13}</notes>',
838 			'</share>'
839 		].join("\n");
840 		ZmShare._XML = new AjxMessageFormat(pattern);
841 	}
842 	return ZmShare._XML;
843 };
844 
845 
846 /**
847  * General method for handling the SOAP call. 
848  * 
849  * <strong>Note:</strong> Exceptions need to be handled by calling method.
850  * 
851  * @private
852  */
853 ZmShare.prototype._shareAction =
854 function(operation, actionAttrs, grantAttrs, callback, batchCmd, notes) {
855 	var soapDoc = AjxSoapDoc.create("FolderActionRequest", "urn:zimbraMail");
856 
857 	var actionNode = soapDoc.set("action");
858 	actionNode.setAttribute("op", operation);
859 	if (this.object.rid && this.object.zid) {
860 		actionNode.setAttribute("id", this.object.zid + ":" + this.object.rid);
861 	} else {
862 		actionNode.setAttribute("id", this.object.id);
863 	}
864 	for (var attr in actionAttrs) {
865 		actionNode.setAttribute(attr, actionAttrs[attr]);
866 	}
867 
868 	if (operation != "!grant") {
869 		var shareNode = soapDoc.set("grant", null, actionNode);
870 		shareNode.setAttribute("gt", this.grantee.type);
871 		if (this.link.inh) {
872 			shareNode.setAttribute("inh", "1");
873 		}
874 		if (!this.isPublic()) {
875 			shareNode.setAttribute("d", this.isGuest() ? (this.grantee.id || this.grantee.name) : this.grantee.name);
876 		}
877 		for (var attr in grantAttrs) {
878 			shareNode.setAttribute(attr, (grantAttrs[attr] || ""));
879 		}
880 	}
881 	var respCallback = new AjxCallback(this, this._handleResponseShareAction, [callback]);
882 	var errorCallback = this._handleErrorShareAction.bind(this, notes);
883 	
884 	if (batchCmd) {
885 		batchCmd.addRequestParams(soapDoc, respCallback, errorCallback);
886 	} else {
887 		appCtxt.getAppController().sendRequest({soapDoc: soapDoc, asyncMode: true,
888 													  callback: respCallback, errorCallback: errorCallback});
889 	}
890 };
891 
892 /*
893 ZmShare.prototype._shareActionJson =
894 function(operation, actionAttrs, grantAttrs, callback, batchCmd) {
895 
896 	var jsonObj = {FolderActionRequest:{_jsns:"urn:zimbraMail"}};
897 	var action = jsonObj.FolderActionRequest.action = {op:operation};
898 	if (this.object.rid && this.object.zid) {
899 		action.id = this.object.zid + ":" + this.object.rid;
900 	} else {
901 		action.id = this.object.id;
902 	}
903 	for (var attr in actionAttrs) {
904 		action.attr = actionAttrs[attr];
905 	}
906 
907 	if (operation != "!grant") {
908 		var share = action.grant = {gt:this.grantee.type};
909 		if (this.link.inh) {
910 			share.inh = "1";
911 		}
912 		if (!this.isPublic()) {
913 			share.d = this.isGuest() ? this.grantee.id : this.grantee.name;
914 		}
915 		for (var attr in grantAttrs) {
916 			share.attr = grantAttrs[attr] || "";
917 		}
918 	}
919 	var respCallback = new AjxCallback(this, this._handleResponseShareAction, [callback]);
920 	var errorCallback = new AjxCallback(this, this._handleErrorShareAction);
921 
922 	if (batchCmd) {
923 		batchCmd.addRequestParams(jsonObj, respCallback, errorCallback);
924 	} else {
925 		appCtxt.getAppController().sendRequest({jsonObj:jsonObj, asyncMode:true,
926 												callback: respCallback, errorCallback: errorCallback});
927 	}
928 };
929 */
930 
931 /**
932  * @private
933  */
934 ZmShare.prototype._handleResponseShareAction =
935 function(callback, result) {
936 	if (callback) {
937 		callback.run(result);
938 	}
939 };
940 
941 /**
942  * @private
943  */
944 ZmShare.prototype._handleErrorShareAction =
945 function(notes, ex) {
946 	var message = ZmMsg.unknownError;
947 	if (ex.isZmCsfeException && ex.code == "account.NO_SUCH_ACCOUNT") {
948 		if (!this._unknownUserFormatter) {
949 			this._unknownUserFormatter = new AjxMessageFormat(ZmMsg.unknownUser);
950 		}
951 		message = this._unknownUserFormatter.format(AjxStringUtil.htmlEncode(this.grantee.name));
952 		// NOTE: This prevents details from being shown
953 		ex = null;
954 	}
955     if (ex.isZmCsfeException && ex.code == "service.PERM_DENIED") {
956         //bug:67698 Displaying proper error message when grantee is owner
957         if(this.object.getOwner() == this.grantee.name){
958             message = ZmMsg.cannotGrantAccessToOwner;
959             ex = null;
960         }
961         else{
962             message = ZmMsg.errorPermission;
963         }
964 	}
965 	if (ex.isZmCsfeException && ex.code == "mail.GRANT_EXISTS") {
966 		this._popupAlreadySharedWarningDialog(notes);
967 		return true;
968 	}
969 
970 	appCtxt.getAppController().popupErrorDialog(message, ex, null, true, null, null, true);
971 	return true;
972 };
973 
974 
975 ZmShare.prototype._popupAlreadySharedWarningDialog =
976 function(notes) {
977     var isPublic = this.isPublic(),
978         fmtMsg,
979         message,
980         dialog;
981 	if (!this._shareExistsFormatter) {
982         fmtMsg = isPublic ? ZmMsg.shareExistsPublic : ZmMsg.shareExists;
983 		this._shareExistsFormatter = new AjxMessageFormat(fmtMsg);
984 	}
985 	message = this._shareExistsFormatter.format(AjxStringUtil.htmlEncode(this.grantee.name));
986 
987 	//creating a dialog for each one of those instead of re-using the singleton dialog from appCtxt for the case you are re-sharing with multiple users already shared. It's not ideal but it would have a warning for each. Since it's rare I think it's good enough for simplicity.
988 	dialog = new DwtMessageDialog({parent:appCtxt._shell, buttons:[DwtDialog.OK_BUTTON, DwtDialog.CANCEL_BUTTON], id:"ResendCancel"});
989 	dialog.getButton(DwtDialog.OK_BUTTON).setText(ZmMsg.resend);
990 	dialog.reset();
991 	dialog.setMessage(message, DwtMessageDialog.WARNING_STYLE);
992 	var dialogcallback = this._sendAnyway.bind(this, notes, ZmShare.NEW,
993 	                                           dialog);
994 	dialog.registerCallback(DwtDialog.OK_BUTTON, dialogcallback);
995     dialog.setButtonEnabled(DwtDialog.OK_BUTTON, !isPublic);
996 	dialog.associateEnterWithButton(DwtDialog.OK_BUTTON);
997 	dialog.popup(null, DwtDialog.OK_BUTTON);
998 };
999 
1000 ZmShare.prototype._sendAnyway =
1001 function(notes, action, dialog) {
1002 	dialog.popdown();
1003 	var callback = this._sendAnywayCallback.bind(this);
1004 	this._sendShareNotification(this.grantee.name, this.object.id,
1005 	                            notes, action, callback);
1006 };
1007 
1008 ZmShare.prototype._sendAnywayCallback =
1009 function() {
1010 	appCtxt.setStatusMsg(ZmMsg.notificationSent, ZmStatusView.LEVEL_INFO);
1011 };
1012 
1013 
1014 /**
1015  * @private
1016  */
1017 ZmShare.prototype._createMsg =
1018 function(mode, addrs, owner) {
1019 	// generate message
1020 	var textPart = this._createTextPart(mode);
1021 	var htmlPart = this._createHtmlPart(mode);
1022 
1023 	var topPart = new ZmMimePart();
1024 	topPart.setContentType(ZmMimeTable.MULTI_ALT);
1025 	topPart.children.add(textPart);
1026 	topPart.children.add(htmlPart);
1027 
1028 	if (mode != ZmShare.NOTIFY) {
1029 		var xmlPart = this._createXmlPart(mode);
1030 		topPart.children.add(xmlPart);
1031 	}
1032 
1033 	var msg = new ZmMailMsg();
1034 	if (mode == ZmShare.ACCEPT || mode == ZmShare.DECLINE) {
1035 		msg.setAddress(AjxEmailAddress.FROM, new AjxEmailAddress(this.grantee.email, AjxEmailAddress.FROM));
1036 		var fromAddrs = new AjxVector();
1037 		if (owner && owner != this.grantor.email) {
1038 			fromAddrs.add(new AjxEmailAddress(owner, AjxEmailAddress.TO));
1039 		}
1040 		fromAddrs.add(new AjxEmailAddress(this.grantor.email, AjxEmailAddress.TO));
1041 		msg.setAddresses(AjxEmailAddress.TO, fromAddrs);
1042 	} else {
1043 		msg.setAddress(AjxEmailAddress.FROM, new AjxEmailAddress(this.grantee.email, AjxEmailAddress.FROM));
1044 		var addrType = (addrs.size() > 1) ? AjxEmailAddress.BCC : AjxEmailAddress.TO;
1045 		msg.setAddresses(addrType, addrs);
1046 	}
1047     //bug:10008 modified subject to support subject normalization for conversation
1048     msg.setSubject(ZmShare._SUBJECTS[mode] + ": " + AjxMessageFormat.format(ZmMsg.sharedBySubject, [this.link.name, this.grantor.name]));	
1049 	msg.setTopPart(topPart);
1050 
1051 	return msg;
1052 };
1053 
1054 /**
1055  * @private
1056  */
1057 ZmShare.prototype._createTextPart =
1058 function(mode) {
1059 	var formatter = ZmShare._getText(mode);
1060 	var content = this._createContent(formatter);
1061 	if (this.notes) {
1062 		var notes = this.notes;
1063 		content = [content, ZmItem.NOTES_SEPARATOR, notes].join("\n");
1064 	}
1065 
1066 	var mimePart = new ZmMimePart();
1067 	mimePart.setContentType(ZmMimeTable.TEXT_PLAIN);
1068 	mimePart.setContent(content);
1069 
1070 	return mimePart;
1071 };
1072 
1073 /**
1074  * @private
1075  */
1076 ZmShare.prototype._createHtmlPart =
1077 function(mode) {
1078 	var formatter = ZmShare._getHtml(mode);
1079 	var content = this._createContent(formatter);
1080 	if (this.notes) {
1081 		formatter = ZmShare._getHtmlNote();
1082 		var notes = AjxStringUtil.nl2br(AjxStringUtil.htmlEncode(this.notes));
1083 		content = [content, formatter.format(notes)].join("");
1084 	}
1085 
1086 	var mimePart = new ZmMimePart();
1087 	mimePart.setContentType(ZmMimeTable.TEXT_HTML);
1088 	mimePart.setContent(content);
1089 
1090 	return mimePart;
1091 };
1092 
1093 /**
1094  * @private
1095  */
1096 ZmShare.prototype._createXmlPart =
1097 function(mode) {
1098 	var folder = (appCtxt.isOffline) ? appCtxt.getFolderTree().getByPath(this.link.name) : null;
1099 	var linkId = (folder) ? folder.id : this.link.id;
1100 	var params = [
1101 		ZmShare.URI, 
1102 		ZmShare.VERSION, 
1103 		mode,
1104 		this.grantee.id, 
1105 		this.grantee.email,
1106 		AjxStringUtil.xmlAttrEncode(this.grantee.name),
1107 		this.grantor.id, 
1108 		this.grantor.email,
1109 		AjxStringUtil.xmlAttrEncode(this.grantor.name),
1110 		linkId,
1111 		AjxStringUtil.xmlAttrEncode(this.link.name), 
1112 		this.link.view, 
1113 		this.link.perm,
1114 		AjxStringUtil.xmlEncode(this.notes)
1115 	];
1116 	var content = ZmShare._getXml().format(params);
1117 
1118 	var mimePart = new ZmMimePart();
1119 	mimePart.setContentType(ZmMimeTable.XML_ZIMBRA_SHARE);
1120 	mimePart.setContent(content);
1121 
1122 	return mimePart;
1123 };
1124 
1125 /**
1126  * @private
1127  */
1128 ZmShare.prototype._createContent =
1129 function(formatter) {
1130 	var role = ZmShare.getRoleFromPerm(this.link.perm);
1131 	var owner = this.object ? (this.object.owner || this.grantor.name) : this.grantor.name;
1132 	owner = AjxStringUtil.htmlEncode(owner);
1133 	var params = [
1134 		AjxStringUtil.htmlEncode(this.link.name),
1135 		"(" + ZmShare._getFolderType(this.link.view) + ")",
1136 		owner,
1137 		AjxStringUtil.htmlEncode(this.grantee.name),
1138 		ZmShare.getRoleName(role),
1139 		ZmShare.getRoleActions(role)
1140 	];
1141 	return formatter.format(params);
1142 };
1143 
1144 ZmShare.getRoleFromPerm = function(perm) {
1145 	if (!perm) { return ZmShare.ROLE_NONE; }
1146 
1147 	if (perm.indexOf(ZmShare.PERM_ADMIN) != -1) {
1148 		return ZmShare.ROLE_ADMIN;
1149 	}
1150 	if (perm.indexOf(ZmShare.PERM_WORKFLOW) != -1) {
1151 		return ZmShare.ROLE_MANAGER;
1152 	}
1153 	if (perm.indexOf(ZmShare.PERM_READ) != -1) {
1154 		return ZmShare.ROLE_VIEWER;
1155 	}
1156 
1157 	return ZmShare.ROLE_NONE;
1158 };
1159 
1160 /**
1161  * Backwards compatibility.
1162  * @private
1163  */
1164 ZmShare._getRoleFromPerm = ZmShare.getRoleFromPerm;
1165 
1166 /**
1167  * Revokes all grants for the given zid (one whose account has been
1168  * removed).
1169  *
1170  * @param {String}	zid			the zimbra ID
1171  * @param {constant}	granteeType	the grantee type (see <code>ZmShare.TYPE_</code> constants)
1172  * @param {AjxCallback}	callback		the client callback
1173  * @param {ZmBatchCommand}	batchCmd		the batch command
1174  */
1175 ZmShare.revokeOrphanGrants =
1176 function(zid, granteeType, callback, batchCmd) {
1177 
1178 	var jsonObj = {
1179 		FolderActionRequest: {
1180 			_jsns:	"urn:zimbraMail",
1181 			action:	{
1182 				op:		"revokeorphangrants",
1183 				id:		ZmFolder.ID_ROOT,
1184 				zid:	zid,
1185 				gt:		granteeType
1186 			}
1187 		}
1188 	};
1189 
1190 	if (batchCmd) {
1191 		var respCallback = new AjxCallback(null, ZmShare._handleResponseRevokeOrphanGrants, [callback]);
1192 		batchCmd.addRequestParams(jsonObj, respCallback);
1193 	} else {
1194 		appCtxt.getRequestMgr().sendRequest({jsonObj:jsonObj, asyncMode:true, callback:respCallback});
1195 	}
1196 };
1197 
1198 /**
1199  * @private
1200  */
1201 ZmShare._handleResponseRevokeOrphanGrants =
1202 function(callback) {
1203 	if (callback) {
1204 		callback.run();
1205 	}
1206 };
1207 
1208 /**
1209  * Creates or updates a ZmShare from share info that comes in JSON form from
1210  * GetShareInfoResponse.
1211  *
1212  * @param shareInfo	[object]		JSON representing share info
1213  * @param share		[ZmShare]*		share to update
1214  */
1215 ZmShare.getShareFromShareInfo =
1216 function(shareInfo, share) {
1217 
1218 	share = share || new ZmShare();
1219 
1220 	// grantee is the user, or a group they belong to
1221 	share.grantee = share.grantee || {};
1222 	if (shareInfo.granteeName)	{ share.grantee.name	= shareInfo.granteeName; }
1223 	if (shareInfo.granteeId)	{ share.grantee.id		= shareInfo.granteeId; }
1224 	if (shareInfo.granteeType)	{ share.grantee.type	= shareInfo.granteeType; }
1225 
1226 	// grantor is the owner of the shared folder
1227 	share.grantor = share.grantor || {};
1228 	if (shareInfo.ownerEmail)	{ share.grantor.email	= shareInfo.ownerEmail; }
1229 	if (shareInfo.ownerName)	{ share.grantor.name	= shareInfo.ownerName; }
1230 	if (shareInfo.ownerId)		{ share.grantor.id		= shareInfo.ownerId; }
1231 
1232 	// link is the shared folder
1233 	share.link = share.link || {};
1234 	share.link.view	= shareInfo.view || "message";
1235 	if (shareInfo.folderId)		{ share.link.id		= shareInfo.folderId; }
1236 	if (shareInfo.folderPath)	{ share.link.path	= shareInfo.folderPath; }
1237 	if (shareInfo.folderPath)	{ share.link.name	= shareInfo.folderPath.substr(shareInfo.folderPath.lastIndexOf("/") + 1); }
1238 	if (shareInfo.rights)		{ share.setPermissions(shareInfo.rights); }
1239 
1240 	// mountpoint is the local folder, if the share has been accepted and mounted
1241 	if (shareInfo.mid) {
1242 		share.mounted		= true;
1243 		share.mountpoint	= share.mountpoint || {};
1244 		share.mountpoint.id	= shareInfo.mid;
1245 		var mtpt = appCtxt.getById(share.mountpoint.id);
1246 		if (mtpt) {
1247 			share.mountpoint.name = mtpt.getName();
1248 			share.mountpoint.path = mtpt.getPath();
1249 		}
1250 	}
1251 
1252 	share.action	= "new";
1253 	share.version	= "0.1";
1254 
1255 	share.type = ZmShare.SHARE;
1256 
1257 	return share;
1258 };
1259 
1260 /**
1261  * Creates or updates a ZmShare from a ZmOrganizer that's a mountpoint. The grantee is
1262  * the current user.
1263  *
1264  * @param link		[ZmFolder]		mountpoint
1265  * @param share		[ZmShare]*		share to update
1266  */
1267 ZmShare.getShareFromLink =
1268 function(link, share) {
1269 
1270 	share = share || new ZmShare();
1271 
1272 	// grantor is the owner of the shared folder
1273 	share.grantor = share.grantor || {};
1274 	if (link.owner)	{ share.grantor.email	= link.owner; }
1275 	if (link.zid)	{ share.grantor.id		= link.zid; }
1276 
1277 	// link is the shared folder
1278 	share.link = share.link || {};
1279 	share.link.view	= ZmOrganizer.VIEWS[link.type][0];
1280 	if (link.rid)	{ share.link.id = link.rid; }
1281 
1282 	var linkShare = link.getMainShare();
1283 	share.link.name = linkShare ? linkShare.link.name : link.name;
1284 	share.setPermissions(linkShare ? linkShare.link.perm : link.perm);
1285 
1286 	// mountpoint is the local folder
1287 	share.mounted = true;
1288 	share.mountpoint = share.mountpoint || {};
1289 	share.mountpoint.id		= link.id;
1290 	share.mountpoint.name	= link.getName();
1291 	share.mountpoint.path	= link.getPath();
1292 
1293 	share.action	= "new";
1294 	share.version	= "0.1";
1295 
1296 	share.type = ZmShare.SHARE;
1297 
1298 	return share;
1299 };
1300 
1301 /**
1302  * Updates a ZmShare that represents a grant
1303  *
1304  * @param share		[ZmShare]		folder grant
1305  * @param oldShare	[ZmShare]*		share to update
1306  */
1307 ZmShare.getShareFromGrant =
1308 function(share, oldShare) {
1309 
1310 	share.link = share.link || {};
1311 	share.link.id	= share.object && (share.object.nId || share.object.id);
1312 	share.link.path = share.object && share.object.getPath();
1313 	share.link.name = share.object && share.object.getName();
1314 
1315 	share.type = ZmShare.GRANT;
1316 	share.domId = oldShare && oldShare.domId;
1317 
1318 	return share;
1319 };
1320