1 /*
  2  * ***** BEGIN LICENSE BLOCK *****
  3  * Zimbra Collaboration Suite Web Client
  4  * Copyright (C) 2009, 2010, 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) 2009, 2010, 2013, 2014, 2015, 2016 Synacor, Inc. All Rights Reserved.
 21  * ***** END LICENSE BLOCK *****
 22  */
 23 
 24 /**
 25  * @overview
 26  */
 27 
 28 /**
 29  * Creates the mobile devices controller.
 30  * @constructor
 31  * @class
 32  * This class represents the mobile devices controller. This controller manages the
 33  * mobile devices page, which has a button toolbar and a list view of the devices.
 34  *
 35  * @author Parag Shah
 36  *
 37  * @param {DwtShell}	container		the shell
 38  * @param {ZmPreferencesApp}	prefsApp		the preferences app
 39  * @param {ZmPrefView}	prefsView		the preferences view
 40  * 
 41  * @extends		ZmController
 42  */
 43 ZmMobileDevicesController = function(container, prefsApp, prefsView) {
 44 
 45 	ZmController.call(this, container, prefsApp);
 46 
 47 	this._prefsView = prefsView;
 48 
 49 	this._devices = new AjxVector();
 50 };
 51 
 52 ZmMobileDevicesController.prototype = new ZmController();
 53 ZmMobileDevicesController.prototype.constructor = ZmMobileDevicesController;
 54 
 55 ZmMobileDevicesController.prototype.toString =
 56 function() {
 57 	return "ZmMobileDevicesController";
 58 };
 59 
 60 /**
 61  * Initializes the controller.
 62  * 
 63  * @param	{ZmToolBar}	toolbar		the toolbar
 64  * @param	{ZmListView}	listView		the list view
 65  */
 66 ZmMobileDevicesController.prototype.initialize =
 67 function(toolbar, listView) {
 68 	// init toolbar
 69 	this._toolbar = toolbar;
 70 	var buttons = this.getToolbarButtons();
 71 	var tbListener = new AjxListener(this, this._toolbarListener);
 72 	for (var i = 0; i < buttons.length; i++) {
 73 		toolbar.addSelectionListener(buttons[i], tbListener);
 74 	}
 75 	this._resetOperations(toolbar, 0);
 76 
 77 	// init list view
 78 	this._listView = listView;
 79 	listView.addSelectionListener(new AjxListener(this, this._listSelectionListener));
 80 };
 81 
 82 ZmMobileDevicesController.prototype.initializeOAuthAppListView =
 83 function(oAuthAppsListView) {
 84     this._oAuthAppsListView = oAuthAppsListView;
 85 };
 86 
 87 ZmMobileDevicesController.prototype.getToolbarButtons =
 88 function() {
 89 	return [
 90 		ZmOperation.MOBILE_REMOVE,
 91 		ZmOperation.SEP,
 92 		ZmOperation.MOBILE_SUSPEND_SYNC,
 93 		ZmOperation.MOBILE_RESUME_SYNC,
 94 		ZmOperation.SEP,
 95 		ZmOperation.MOBILE_WIPE
 96 	];
 97 };
 98 
 99 ZmMobileDevicesController.prototype.loadDeviceInfo =
100 function() {
101 	var soapDoc = AjxSoapDoc.create("GetDeviceStatusRequest", "urn:zimbraSync");
102 	var respCallback = new AjxCallback(this, this._handleResponseLoadDevices);
103 	appCtxt.getAppController().sendRequest({soapDoc:soapDoc, asyncMode:true, callback:respCallback});
104 };
105 
106 ZmMobileDevicesController.prototype._handleResponseLoadDevices =
107 function(results) {
108     // clean up
109     this._devices.removeAll();
110     this._devices = new AjxVector();
111 
112     var list = results.getResponse().GetDeviceStatusResponse.device;
113     if (list && list.length) {
114         for (var i = 0; i < list.length; i++) {
115             this._devices.add(new ZmMobileDevice(list[i]));
116         }
117     }
118 
119     this._listView.set(this._devices);
120     this._resetOperations(this._toolbar);
121 };
122 
123 ZmMobileDevicesController.prototype.loadOAuthConsumerAppInfo =
124 function() {
125     var jsonObj = { GetOAuthConsumersRequest : { _jsns:"urn:zimbraAccount"}};
126     var callback = this._handleResponseLoadOAuthConsumer.bind(this);
127     appCtxt.getRequestMgr().sendRequest({jsonObj:jsonObj, asyncMode:true, callback:callback});
128 };
129 
130 ZmMobileDevicesController.prototype._handleResponseLoadOAuthConsumer =
131 function(result){
132     if (this._oAuthConsumerApps) {
133         this._oAuthConsumerApps.removeAll();
134     }
135     this._oAuthConsumerApps = new AjxVector();
136 
137     var response = result.getResponse();
138     var OAuthConsumersResponse = response.GetOAuthConsumersResponse;
139     var list = OAuthConsumersResponse.OAuthConsumer;
140     if (list && list.length) {
141         for (var i = 0; i < list.length; i++) {
142             this._oAuthConsumerApps.add(new ZmOAuthConsumerApp(list[i]));
143         }
144     }
145     this._oAuthAppsListView.set(this._oAuthConsumerApps);
146 };
147 
148 /**
149  * Handles left-clicking on a rule. Double click opens up a rule for editing.
150  *
151  * @param	{DwtEvent}	ev		the click event
152  * 
153  * @private
154  */
155 ZmMobileDevicesController.prototype._listSelectionListener =
156 function(ev) {
157 	if (ev.detail == DwtListView.ITEM_DBL_CLICKED) {
158 		var device = this._listView.getSelection()[0];
159 		this._showMoreDetails(device);
160 	} else {
161 		this._resetOperations(this._toolbar, 1);
162 	}
163 };
164 
165 ZmMobileDevicesController.prototype._showMoreDetails =
166 function(device) {
167 	var msg = AjxTemplate.expand("prefs.Pages#MobileDeviceInfo", {device:device});
168 	var dlg = appCtxt.getMsgDialog();
169 	dlg.setMessage(msg);
170 	dlg.popup();
171 };
172 
173 
174 // Listeners
175 
176 ZmMobileDevicesController.prototype._toolbarListener =
177 function(ev) {
178 	var item = this._listView.getSelection()[0];
179 	var id = ev.item.getData(ZmOperation.KEY_ID);
180 	var callback = new AjxCallback(this, this._handleAction, [item, id]);
181 	var action = ev.item.getData(ZmOperation.KEY_ID);
182 
183 	if (action == ZmOperation.MOBILE_WIPE) {
184 		// if the item status is wipe-requested, then, user wants to cancel
185 		if (item.status == ZmMobileDevice.STATUS_REMOTE_WIPE_REQUESTED) {
186 			action = ZmOperation.MOBILE_CANCEL_WIPE;
187 		} else {
188 			// bug 42135: add confirmation for mobile wipe
189 			var dialog = appCtxt.getOkCancelMsgDialog();
190 			dialog.setMessage(ZmMsg.mobileDeviceWipeConfirm);
191 			dialog.registerCallback(DwtDialog.OK_BUTTON, this._handleDeviceWipe, this, [dialog, item, callback]);
192 			dialog.popup();
193 			return;
194 		}
195 	}
196 
197 	item.doAction(action, callback);
198 };
199 
200 ZmMobileDevicesController.prototype._handleDeviceWipe =
201 function(dialog, item, callback) {
202 	dialog.popdown();
203 	item.doAction(ZmOperation.MOBILE_WIPE, callback);
204 };
205 
206 ZmMobileDevicesController.prototype._handleAction =
207 function(item, id) {
208 	if (id == ZmOperation.MOBILE_REMOVE) {
209 		this._listView.removeItem(item, true);
210 		this._devices.remove(item);
211 		this._resetOperations(this._toolbar, 0);
212 		return;
213 	}
214 
215 	if (id == ZmOperation.MOBILE_WIPE) {
216 		this._toolbar.getButton(ZmOperation.MOBILE_WIPE).setText(ZmMsg.mobileWipeCancel);
217 	}
218 
219 	this._listView.redrawItem(item);
220 	this._listView.setSelection(item, true);
221 	this._resetOperations(this._toolbar, 1);
222 };
223 
224 /**
225 * Resets the toolbar button states, depending on which device is selected.
226 *
227 * @param parent		[ZmButtonToolBar]	the toolbar
228 * @param numSel		[int]				number of rules selected (0 or 1)
229 */
230 ZmMobileDevicesController.prototype._resetOperations =
231 function(parent, numSel) {
232 	if (numSel == 1) {
233 		var item = this._listView.getSelection()[0];
234 		var status = item.getStatus();
235 		if (item.id == "AppleBADBAD") {
236 			status = ZmMobileDevice.STATUS_REMOTE_WIPE_REQUESTED;
237 		}
238 
239 		parent.enableAll(true);
240 		parent.enable(ZmOperation.MOBILE_RESUME_SYNC, false);
241 
242 		if (status == ZmMobileDevice.STATUS_SUSPENDED) {
243 			parent.enable(ZmOperation.MOBILE_SUSPEND_SYNC, false);
244 			parent.enable(ZmOperation.MOBILE_RESUME_SYNC, true);
245 		}
246 		else {
247 			var button = parent.getButton(ZmOperation.MOBILE_WIPE);
248 			if (button) {
249 				if (status == ZmMobileDevice.STATUS_REMOTE_WIPE_REQUESTED) {
250 					button.setText(ZmMsg.mobileWipeCancel);
251 					button.setImage("MobileWipeCancel");
252 				} else {
253 					button.setText(ZmMsg.mobileWipe);
254 					button.setImage("MobileWipe");
255 				}
256 			}
257 			if (status === ZmMobileDevice.STATUS_REMOTE_WIPE_COMPLETE) {
258 				parent.enable(ZmOperation.MOBILE_WIPE, false);
259 			}
260 
261 		}
262 
263 		if (!item.provisionable) {
264 			parent.enable(ZmOperation.MOBILE_WIPE, false);
265 		}
266 	}
267 	else {
268 		parent.enableAll(false);
269 	}
270 };
271 
272 ZmMobileDevicesController.handleRemoveOauthConsumerApp = function(removeLinkEle, oAuthAccessToken, oAuthAppName, oAuthDevice) {
273     var dialog = appCtxt.getOkCancelMsgDialog();
274     var dialogContent = AjxMessageFormat.format(ZmMsg.oAuthAppAuthorizationRemoveConfirm, [oAuthAppName, oAuthDevice]);
275     dialog.setMessage(dialogContent, DwtMessageDialog.CRITICAL_STYLE, ZmMsg.removeOAuthAppAuthorization);
276     dialog.registerCallback(DwtDialog.OK_BUTTON, ZmMobileDevicesController.removeOauthConsumerApp.bind(null, removeLinkEle, dialog, oAuthAccessToken, oAuthAppName, oAuthDevice));
277     dialog.popup();
278 };
279 
280 ZmMobileDevicesController.removeOauthConsumerApp = function(removeLinkEle, dialog, oAuthAccessToken, oAuthAppName, oAuthDevice) {
281      var jsonObj = { RevokeOAuthConsumerRequest : { _jsns:"urn:zimbraAccount", accessToken:{ _content : oAuthAccessToken}}};
282      var callback = ZmMobileDevicesController.removeOauthConsumerAppCallback.bind(null, removeLinkEle, dialog);
283      appCtxt.getRequestMgr().sendRequest({jsonObj:jsonObj, asyncMode:true, callback:callback});
284 };
285 
286 ZmMobileDevicesController.removeOauthConsumerAppCallback = function(removeLinkEle, dialog) {
287     dialog.popdown();
288     Dwt.setVisible(removeLinkEle, false);
289 };