1 /*
  2  * ***** BEGIN LICENSE BLOCK *****
  3  * Zimbra Collaboration Suite Web Client
  4  * Copyright (C) 2008, 2009, 2010, 2011, 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) 2008, 2009, 2010, 2011, 2013, 2014, 2016 Synacor, Inc. All Rights Reserved.
 21  * ***** END LICENSE BLOCK *****
 22  */
 23 
 24 /**
 25  * Creates a doclet manager.
 26  * @class
 27  * This class represents a doclet manager.
 28  * 
 29  */
 30 ZmDocletMgr = function() {
 31 };
 32 
 33 ZmDocletMgr.prototype.saveDocument =
 34 function(item) {
 35     this._uploadSaveDocs2([{id: item.id, name: item.name, version: (item.version ? item.version :1), folderId: item.folderId}], null, null, item.name, item.content, item.contentType, item.descEnabled, item.desc);
 36 };
 37 
 38 ZmDocletMgr.prototype._uploadSaveDocs2 =
 39 function(files, status, guids, name, content, ct, enableDesc, desc) {
 40     // create document wrappers
 41     var soapDoc = AjxSoapDoc.create("BatchRequest", "urn:zimbra", null);
 42     soapDoc.setMethodAttribute("onerror", "continue");
 43     for (var i = 0; i < files.length; i++) {
 44         var file = files[i];
 45         if (file.done) continue;
 46 
 47         var saveDocNode = soapDoc.set("SaveDocumentRequest", null, null, "urn:zimbraMail");
 48         saveDocNode.setAttribute("requestId", i);
 49 
 50         var docNode = soapDoc.set("doc", null, saveDocNode);
 51         if (file.id) {
 52             docNode.setAttribute("id", file.id);
 53             docNode.setAttribute("ver", file.version);
 54         }
 55         else {
 56             docNode.setAttribute("l", file.folderId);
 57         }
 58 
 59         if(ct){
 60             docNode.setAttribute("ct", ct);
 61         }
 62 
 63         if(file.guid) {
 64             var uploadNode = soapDoc.set("upload", null, docNode);
 65             uploadNode.setAttribute("id", file.guid);
 66         }
 67 
 68         if(name!=null && content!=null) {
 69             var contentNode = soapDoc.set("content", content, docNode);
 70             docNode.setAttribute("name", name);
 71         }
 72 
 73         docNode.setAttribute("descEnabled", enableDesc ? "true" : "false");
 74         if(desc){
 75             docNode.setAttribute("desc", desc);
 76         }
 77     }
 78 
 79     var args = [ files, status, guids ];
 80     var callback = new AjxCallback(this, this._uploadSaveDocsResponse, args);
 81     var params = {
 82         soapDoc:soapDoc,
 83         asyncMode:true,
 84         callback:callback
 85     };
 86 
 87     var parentAppCtxt = window.opener && window.opener.appCtxt;
 88 	if (parentAppCtxt) {
 89         var acct = parentAppCtxt.getActiveAccount();
 90         params.accountName = (acct && acct.id != ZmAccountList.DEFAULT_ID) ? acct.name : null;
 91     }
 92     this.sendRequest(params);
 93 };
 94 
 95 /**
 96  * Sends the request.
 97  * 
 98  * @param	{Hash}	params		a hash of parameters
 99  * 
100  * @see			ZmRequestMgr
101  * @see			ZmRequestMgr.sendRequest
102  */
103 ZmDocletMgr.prototype.sendRequest =
104 function(params) {
105     if(!this._requestMgr) {
106         this._requestMgr = new ZmRequestMgr(this);
107     }
108     params.noSession = true;
109     return this._requestMgr.sendRequest(params);
110 };
111 
112 ZmDocletMgr.prototype._uploadSaveDocsResponse =
113 function(files, status, guids, response) {
114     var resp = response && response._data && response._data.BatchResponse;
115 
116     var folderIds = [];
117 
118     // mark successful uploads
119     if (resp && resp.SaveDocumentResponse) {
120         for (var i = 0; i < resp.SaveDocumentResponse.length; i++) {
121             var saveDocResp = resp.SaveDocumentResponse[i];
122             files[saveDocResp.requestId].done = true;
123             files[saveDocResp.requestId].rest = saveDocResp.doc[0].rest;
124             files[saveDocResp.requestId].ver = saveDocResp.doc[0].ver;
125             files[saveDocResp.requestId].id = saveDocResp.doc[0].id;
126             if(files[saveDocResp.requestId].folderId) {
127                 folderIds.push(files[saveDocResp.requestId].folderId);
128             }
129         }
130     }
131 
132     // check for conflicts
133     var conflicts = null;
134     if (resp && resp.Fault) {
135         var errors = [];
136         conflicts = [];
137         for (var i = 0; i < resp.Fault.length; i++) {
138             var fault = resp.Fault[i];
139             var error = fault.Detail.Error;
140             var code = error.Code;
141             var attrs = error.a;
142             if (code == ZmCsfeException.MAIL_ALREADY_EXISTS ||
143                 code == ZmCsfeException.MODIFY_CONFLICT) {
144                 var file = files[fault.requestId];
145                 for (var p in attrs) {
146                     var attr = attrs[p];
147                     switch (attr.n) {
148                         case "id": { file.id = attr._content; break; }
149                         case "ver": { file.version = attr._content; break; }
150                         case "rest": { file.rest = attr._content; break; }
151 
152                     }
153                 }
154                 conflicts.push(file);
155             }
156             else {
157                 DBG.println("Unknown error occurred: "+code);
158                 errors[fault.requestId] = fault;
159             }
160         }
161         // TODO: What to do about other errors?
162     }
163 
164 	// poke parent window to get notifications
165 	var parentAppCtxt = window.opener && window.opener.appCtxt;
166 	var parentAppCtlr = parentAppCtxt && parentAppCtxt.getAppController();
167 	if (parentAppCtlr && !parentAppCtlr.getInstantNotify()) {
168 		parentAppCtlr.sendNoOp();
169 	}
170 
171     if (this._saveCallback) {
172         //Pass on the conflicts to callback
173         this._saveCallback.run(files, conflicts);
174     }
175 };
176 
177 ZmDocletMgr.prototype.setSaveCallback =
178 function(callback) {
179   this._saveCallback = callback;  
180 
181 };
182 
183 ZmDocletMgr.prototype._kickPolling =
184 function(resetBackoff) {
185 
186 };
187 
188 ZmDocletMgr.prototype._handleException =
189 function(ex, continuation) {
190     //todo: handle exceptions
191 };
192 
193 ZmDocletMgr.prototype.runAppFunction =
194 function(funcName, force) {
195     //not needed in new function
196 };
197 
198 ZmDocletMgr.prototype.fetchDocumentContent =
199 function(item) {
200     var restURL = item.rest;
201     var urlParts = AjxStringUtil.parseURL(restURL);
202     if(urlParts && urlParts.path) {
203         var result = AjxRpc.invoke("", urlParts.path + "?fmt=native&ver=" + item.version, {}, null, true);
204         var docContent = "";
205         if(result && result.success) {
206             docContent = this._pendingContent = result.text;
207         }
208         return docContent;
209     }
210     return "";
211 };
212 
213 
214 ZmDocletMgr.prototype.getItemInfo =
215 function(params)
216 {
217     var soapDoc = AjxSoapDoc.create("GetItemRequest", "urn:zimbraMail");
218     var folderNode = soapDoc.set("item");
219 
220     if(params.path){
221         folderNode.setAttribute("path", params.path);
222     }else if(params.folderId && params.id){ //bug:19658
223         folderNode.setAttribute("l", params.folderId);
224         folderNode.setAttribute("id", params.id);
225     }else if(params.folderId && params.name){
226         folderNode.setAttribute("l", params.folderId);
227         folderNode.setAttribute("name", params.name);
228     }else if(params.id){
229         folderNode.setAttribute("id", params.id);
230     }
231 
232     var args = [];
233     var asyncMode = (params.callback?true:false);
234 
235     var handleResponse = null;
236     if(asyncMode){
237         handleResponse = new AjxCallback(this, this.handleGetItemResponse,[params]);
238     }
239 
240     var parentAppCtxt = window.opener && window.opener.appCtxt;
241     if (parentAppCtxt && parentAppCtxt.multiAccounts) {
242         var acct = parentAppCtxt.getActiveAccount();
243         params.accountName = acct && acct.name;
244     }
245 
246     var reqParams = {
247         soapDoc: soapDoc,
248         asyncMode: asyncMode,
249         callback: handleResponse,
250         accountName: params.accountName
251     };
252 
253     var response = this.sendRequest(reqParams);
254 
255     if(!asyncMode && response){
256         var item = this.handleGetItemResponse(params,response.GetItemResponse);
257         return item;
258     }
259 
260     return null;
261 };
262 
263 ZmDocletMgr.prototype.handleGetItemResponse =
264 function(params,response)
265 {
266 
267     var path = params.path;
268     var callback = params.callback;
269 
270     var getItemResponse = response;
271     if(response && response._data){
272         getItemResponse = response && response._data && response._data.GetItemResponse;
273     }
274 
275     var docResp = getItemResponse && getItemResponse.doc && getItemResponse.doc[0];
276 
277     var item = null;
278 
279     if(docResp){
280         item = new ZmItem();
281         var data = docResp;
282         if (data.id) item.id = data.id;        
283         if (data.rest) item.rest = data.rest;
284         if (data.l) item.folderId = data.l;
285         if (data.name) item.name = data.name;
286         if (data.cr) item.creator = data.cr;
287         if (data.d) item.createDate = new Date(Number(data.d));
288         if (data.md) item.modifyDate = new Date(Number(data.md));
289         if (data.leb) item.modifier = data.leb;
290         if (data.s) item.size = Number(data.s);
291         if (data.ver) item.version = Number(data.ver);
292         if (data.ct) item.contentType = data.ct.split(";")[0];
293         item.folderId = docResp.l || ZmOrganizer.ID_BRIEFCASE;
294         item.locked = false;
295         if (data.loid)    {
296             item.locked = true;
297             item.lockId = data.loid;
298             item.lockUser = data.loe;
299             item.lockTime = new Date(Number(data.lt));
300         }
301         item.descEnabled = data.descEnabled;
302     }
303 
304     if(callback){
305         callback.run(item);
306     }
307 
308     return item;
309 };
310 
311 ZmDocletMgr.createItem = function(response) {
312     var docletMgr = new ZmDocletMgr();
313     return docletMgr.handleGetItemResponse({}, response);
314 };
315 
316 ZmDocletMgr.prototype.getThemeContent =
317 function(themePath)
318 {
319     if(!themePath)  return '';
320 
321     var result = AjxRpc.invoke("", themePath, {}, null, true);
322     var docContent = "";
323     if(result && result.success) {
324         docContent = result.text;
325     }
326     return docContent;
327 };
328 
329 ZmDocletMgr.prototype.checkInvalidDocName = function(fileName) {
330 
331     var message;
332     fileName = fileName.replace(/^\s+/,"").replace(/\s+$/,"");
333 
334     if(fileName == ""){
335         message = ZmMsg.emptyDocName;
336     }else if (!ZmOrganizer.VALID_NAME_RE.test(fileName) || ZmAppCtxt.INVALID_NAME_CHARS_RE.test(fileName)) {
337         //Bug fix # 79986 - < > , ? | / \ * : are invalid filenames
338         message = AjxMessageFormat.format(ZmMsg.errorInvalidName, AjxStringUtil.htmlEncode(fileName));
339     } else if ( fileName.length > ZmOrganizer.MAX_NAME_LENGTH){
340         message = AjxMessageFormat.format(ZmMsg.nameTooLong, ZmOrganizer.MAX_NAME_LENGTH);
341     }
342 
343     return message;
344 };
345 
346 ZmDocletMgr.prototype.unlock =
347 function(item, callback, errorCallback, accountName){
348 
349     var json = {
350 		ItemActionRequest: {
351 			_jsns: "urn:zimbraMail",
352 			action: {
353 				id:	item.id,
354 				op:	"unlock"
355 			}
356 		}
357 	};
358 
359 	var params = {
360 		jsonObj:		json,
361 		asyncMode:		Boolean(callback),
362 		callback:		callback,
363 		errorCallback:	errorCallback,
364 		accountName:	accountName
365 	};
366 	return this.sendRequest(params);
367 
368 };
369