1 /* 2 * ***** BEGIN LICENSE BLOCK ***** 3 * Zimbra Collaboration Suite Web Client 4 * Copyright (C) 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) 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Synacor, Inc. All Rights Reserved. 21 * ***** END LICENSE BLOCK ***** 22 */ 23 24 ZmAccountsPage = function(parent, section, controller) { 25 // bug: 20458 - We don't have ZmDataSource and other classes unless 26 // we load MailCore (which we never do if mail is disabled). 27 ZmAccountsPage._definePrefs(); 28 ZmAccountsPage._defineClasses(); 29 30 ZmPreferencesPage.call(this, parent, section, controller); 31 32 this._sectionDivs = {}; 33 this._accounts = new AjxVector(); 34 this._deletedAccounts = []; 35 }; 36 ZmAccountsPage.prototype = new ZmPreferencesPage; 37 ZmAccountsPage.prototype.constructor = ZmAccountsPage; 38 39 ZmAccountsPage.prototype.toString = 40 function() { 41 return "ZmAccountsPage"; 42 }; 43 44 // 45 // Constants 46 // 47 48 // pref values 49 50 ZmAccountsPage.DOWNLOAD_TO_INBOX = ZmOrganizer.ID_INBOX; 51 ZmAccountsPage.DOWNLOAD_TO_FOLDER = -1; 52 53 // counters 54 55 ZmAccountsPage.__personaCount = 0; 56 ZmAccountsPage.__externalCount = 0; 57 58 // section prefs 59 60 ZmAccountsPage._definePrefs = 61 function() { 62 ZmAccountsPage.PREFS = { 63 // Primary / Common 64 ALERT: { 65 displayContainer: ZmPref.TYPE_CUSTOM 66 }, 67 PROVIDER: { 68 displayContainer: ZmPref.TYPE_SELECT 69 }, 70 NAME: { 71 displayContainer: ZmPref.TYPE_INPUT 72 }, 73 HEADER: { 74 displayContainer: ZmPref.TYPE_STATIC, 75 displayName: ZmMsg.accountSubHeader 76 }, 77 EMAIL: { 78 displayContainer: ZmPref.TYPE_INPUT, 79 hint: ZmMsg.exampleEmailAddr 80 }, 81 VISIBLE: { 82 displayContainer: ZmPref.TYPE_CHECKBOX 83 }, 84 REPLY_TO: { 85 displayName: ZmMsg.accountReplyTo, 86 displayContainer: ZmPref.TYPE_CHECKBOX 87 }, 88 REPLY_TO_NAME: { 89 displayContainer: ZmPref.TYPE_INPUT, 90 hint: ZmMsg.exampleEmailName 91 }, 92 REPLY_TO_EMAIL: { 93 displayContainer: ZmPref.TYPE_COMBOBOX, 94 hint: ZmMsg.emailAddr 95 }, 96 // External 97 ACCOUNT_TYPE: { 98 displayContainer: ZmPref.TYPE_RADIO_GROUP, 99 orientation: ZmPref.ORIENT_HORIZONTAL, 100 displayOptions: ["POP3", "IMAP"], // TODO: i18n 101 options: [ZmAccount.TYPE_POP, ZmAccount.TYPE_IMAP] 102 }, 103 USERNAME: { 104 displayContainer: ZmPref.TYPE_INPUT 105 }, 106 HOST: { 107 displayContainer: ZmPref.TYPE_INPUT, 108 hint: ZmMsg.exampleMailServer 109 }, 110 PASSWORD: { 111 // TODO: rename ZmPref.TYPE_PASSWORD to TYPE_CHANGE_PASSWORD 112 // TODO: add ZmPref.TYPE_PASSWORD 113 displayContainer: ZmPref.TYPE_INPUT 114 }, 115 CHANGE_PORT: { 116 displayName: ZmMsg.accountChangePortLabel, 117 displayContainer: ZmPref.TYPE_CHECKBOX 118 }, 119 PORT: { 120 displayContainer: ZmPref.TYPE_INPUT, 121 validator: DwtInputField.validateNumber 122 }, 123 PORT_DEFAULT: { 124 displayContainer: ZmPref.TYPE_STATIC, 125 displayName: ZmMsg.accountPortDefault 126 }, 127 SSL: { 128 displayName: ZmMsg.accountUseSSL, 129 displayContainer: ZmPref.TYPE_CHECKBOX, 130 options: [ZmDataSource.CONNECT_CLEAR, ZmDataSource.CONNECT_SSL] 131 }, 132 TEST: { 133 displayName: ZmMsg.accountTest, 134 displayContainer: ZmPref.TYPE_CUSTOM // NOTE: a button 135 }, 136 DOWNLOAD_TO: { 137 displayContainer: ZmPref.TYPE_RADIO_GROUP, 138 displayOptions: [ZmMsg.accountDownloadToInbox, ZmMsg.accountDownloadToFolder], 139 options: [ZmAccountsPage.DOWNLOAD_TO_INBOX, ZmAccountsPage.DOWNLOAD_TO_FOLDER] 140 }, 141 DELETE_AFTER_DOWNLOAD: { 142 displayName: ZmMsg.accountDeleteAfterDownload, 143 displayContainer: ZmPref.TYPE_CHECKBOX 144 }, 145 // Persona 146 FROM_NAME: { 147 displayContainer: ZmPref.TYPE_INPUT, 148 hint: ZmMsg.exampleEmailName 149 }, 150 FROM_EMAIL: { 151 displayContainer: ZmPref.TYPE_SELECT, 152 hint: ZmMsg.emailAddr 153 }, 154 FROM_EMAIL_TYPE: { 155 displayContainer: ZmPref.TYPE_SELECT, 156 hint: ZmMsg.emailAddr 157 }, 158 WHEN_SENT_TO: { 159 displayName: ZmMsg.personaWhenSentTo, 160 displayContainer: ZmPref.TYPE_CHECKBOX 161 }, 162 WHEN_SENT_TO_LIST: { 163 displayContainer: ZmPref.TYPE_INPUT 164 }, 165 WHEN_IN_FOLDER: { 166 displayName: ZmMsg.personaWhenInFolder, 167 displayContainer: ZmPref.TYPE_CHECKBOX 168 }, 169 WHEN_IN_FOLDER_LIST: { 170 displayContainer: ZmPref.TYPE_INPUT, 171 hint: ZmMsg.exampleFolderNames 172 }, 173 WHEN_IN_FOLDER_BUTTON: { 174 displayContainer: ZmPref.TYPE_CUSTOM 175 } 176 }; 177 178 /** 179 * Defines the various account sections. Each section has a list of "prefs" 180 * that may appear in that section. In the code below, each pref is marked 181 * as "A" if it's a field on the account object and "I" if it's a field on 182 * the identity object. 183 */ 184 ZmAccountsPage.SECTIONS = { 185 PRIMARY: { 186 id: "PRIMARY", 187 prefs: [ 188 "NAME", // A 189 "HEADER", // 190 "EMAIL", // A 191 "VISIBLE", // 192 "FROM_NAME", // I 193 "FROM_EMAIL", // I 194 "FROM_EMAIL_TYPE", // I 195 "REPLY_TO", // I 196 "REPLY_TO_NAME", // I 197 "REPLY_TO_EMAIL" // I 198 ] 199 }, 200 EXTERNAL: { 201 id: "EXTERNAL", 202 prefs: [ 203 "ALERT", 204 "PROVIDER", 205 "NAME", // A 206 "HEADER", 207 "EMAIL", // I - maps to from name in identity 208 "ACCOUNT_TYPE", // A 209 "USERNAME", // A 210 "HOST", // A 211 "PASSWORD", // A 212 "CHANGE_PORT", 213 "PORT", // A 214 "PORT_DEFAULT", 215 "SSL", // A 216 "TEST", 217 "DOWNLOAD_TO", // A 218 "DELETE_AFTER_DOWNLOAD", // A 219 "FROM_NAME", // I 220 "FROM_EMAIL", // I 221 "REPLY_TO", // I 222 "REPLY_TO_NAME", // I 223 "REPLY_TO_EMAIL" // I 224 ] 225 }, 226 PERSONA: { 227 id: "PERSONA", 228 prefs: [ 229 "NAME", // I 230 "HEADER", 231 "FROM_NAME", // I 232 "FROM_EMAIL", // I 233 "FROM_EMAIL_TYPE", // I 234 "REPLY_TO", // I 235 "REPLY_TO_NAME", // I 236 "REPLY_TO_EMAIL", // I 237 "WHEN_SENT_TO", // I 238 "WHEN_SENT_TO_LIST", // I 239 "WHEN_IN_FOLDER", // I 240 "WHEN_IN_FOLDER_LIST", // I 241 "WHEN_IN_FOLDER_BUTTON" 242 ] 243 } 244 }; 245 246 /*** DEBUG *** 247 var providers = [ 248 { id: "yahoo-pop", name: "Yahoo! Mail", type: "POP", host: "yahoo.com" }, 249 { id: "gmail-pop", name: "GMail (POP)", type: "POP", host: "pop.gmail.com", connectionType: "ssl" }, 250 { id: "gmail-imap", name: "GMail (IMAP)", type: "IMAP", host: "imap.gmail.com", connectionType: "ssl" } 251 ]; 252 for (var i = 0; i < providers.length; i++) { 253 ZmDataSource.addProvider(providers[i]); 254 } 255 /***/ 256 257 // create a section for each provider with a custom template 258 var providers = ZmDataSource.getProviders(); 259 for (var id in providers) { 260 if (!AjxTemplate.getTemplate("prefs.Pages#ExternalAccount-"+id)) { continue; } 261 ZmAccountsPage.SECTIONS[id] = { 262 id: id, 263 prefs: ZmAccountsPage.SECTIONS["EXTERNAL"].prefs 264 }; 265 } 266 267 }; // function ZmAccountsPage._definePrefs 268 269 ZmAccountsPage.ACCOUNT_PROPS = { 270 "NAME": { setter: "setName", getter: "getName" }, 271 "EMAIL": { setter: "setEmail", getter: "getEmail" }, 272 "EMAIL_TYPE": "emailType", 273 "VISIBLE": "visible", 274 "ACCOUNT_TYPE": "type", 275 "USERNAME": "userName", 276 "HOST": "mailServer", 277 "PASSWORD": "password", 278 "PORT": "port", 279 "SSL": "connectionType", 280 "DOWNLOAD_TO": { setter: "setFolderId", getter: "getFolderId" }, 281 "DELETE_AFTER_DOWNLOAD": "leaveOnServer" 282 }; 283 284 ZmAccountsPage.IDENTITY_PROPS = { 285 "FROM_NAME": "sendFromDisplay", 286 "FROM_EMAIL": "sendFromAddress", 287 "FROM_EMAIL_TYPE": "sendFromAddressType", 288 "REPLY_TO": "setReplyTo", 289 "REPLY_TO_NAME": "setReplyToDisplay", 290 "REPLY_TO_EMAIL": "setReplyToAddress", 291 "WHEN_SENT_TO": "useWhenSentTo", 292 "WHEN_SENT_TO_LIST": "whenSentToAddresses", 293 "WHEN_IN_FOLDER": "useWhenInFolder", 294 "WHEN_IN_FOLDER_LIST": "whenInFolderIds" 295 }; 296 297 ZmAccountsPage.prototype._handleTwoStepAuthLink = 298 function(params) { 299 if (appCtxt.get(ZmSetting.TWO_FACTOR_AUTH_ENABLED)) { 300 var dialog = appCtxt.getYesNoMsgDialog(); 301 dialog.setMessage(ZmMsg.twoStepAuthDisableConfirm, DwtMessageDialog.CRITICAL_STYLE, ZmMsg.twoStepAuthDisable); 302 dialog.registerCallback(DwtDialog.YES_BUTTON, ZmTwoFactorSetupDialog.disableTwoFactorAuth.bind(window, params, dialog)); 303 } 304 else { 305 if (!this._twoFactorSetupDialog) { 306 this._twoFactorSetupDialog = new ZmTwoFactorSetupDialog(params); 307 } 308 var dialog = this._twoFactorSetupDialog; 309 } 310 dialog.popup(); 311 }; 312 313 ZmAccountsPage.prototype._handleTwoStepAuthCodesViewLink = 314 function(params) { 315 if (!this._oneTimeCodesDialog) { 316 this._oneTimeCodesDialog = new ZmOneTimeCodesDialog(params); 317 } 318 this._oneTimeCodesDialog.popup(); 319 }; 320 321 ZmAccountsPage.prototype.getGrantRightsDlg = 322 function(callback) { 323 324 if (!this._grantRightsDlg) { 325 this._grantRightsDlg = new ZmGrantRightsDialog(appCtxt.getShell(), "ZmGrantRightsDialog"); 326 } 327 this._grantRightsDlg._okCallBack = callback; 328 return this._grantRightsDlg; 329 330 }; 331 332 ZmAccountsPage.prototype._errRightsCommand = 333 function(user, ex) { 334 this._delegateErrFormatter = this._delegateErrFormatter || new AjxMessageFormat(ZmMsg.delegateNoSuchAccErr); 335 var msg = this._delegateErrFormatter.format(user); 336 if (ex.code === "account.NO_SUCH_ACCOUNT") { 337 appCtxt.getAppController().popupErrorDialog(msg, ex); 338 return true; 339 } 340 341 return false; 342 343 }; 344 345 ZmAccountsPage.prototype._handleDelegateRights = 346 function(user, sendAs, sendObo, isGrant, refresh) { 347 var request = isGrant ? "GrantRightsRequest" : "RevokeRightsRequest"; 348 var soapDoc = AjxSoapDoc.create(request, "urn:zimbraAccount"); 349 var batchCmd = new ZmBatchCommand(null, appCtxt.accountList.mainAccount.name); 350 var callback = this._handleDelegateRightsCallback.bind(this, user, sendAs, sendObo, isGrant, refresh); 351 var errCallback = this._errRightsCommand.bind(this, user); 352 var aceNode = null; 353 if (sendAs){ 354 aceNode = soapDoc.set("ace"); 355 aceNode.setAttribute("gt", "usr"); 356 aceNode.setAttribute("d", user); 357 aceNode.setAttribute("right", ZmSetting.SEND_AS); 358 } 359 360 if (sendObo){ 361 aceNode = soapDoc.set("ace"); 362 aceNode.setAttribute("gt", "usr"); 363 aceNode.setAttribute("d", user); 364 aceNode.setAttribute("right", ZmSetting.SEND_ON_BEHALF_OF); 365 } 366 367 batchCmd.addNewRequestParams(soapDoc, callback, errCallback); 368 batchCmd.run(); 369 }; 370 371 ZmAccountsPage.prototype._handleDelegateRightsCallback = 372 function(user, sendAs, sendObo, isGrant, refresh, result){ 373 var email = user; 374 if (isGrant){ 375 var response = result.getResponse(); 376 var aces = response && response.GrantRightsResponse && response.GrantRightsResponse.ace; 377 if (aces && aces.length && aces[0].d) 378 email = aces[0].d; 379 } 380 if (refresh) { 381 this._getGrants(); 382 } 383 this._sendGrantRightsMessage(appCtxt.accountList.mainAccount.name, email, sendAs, sendObo, isGrant); 384 385 }; 386 387 ZmAccountsPage.prototype._grantDelegateRights = 388 function(user, sendAs, sendObo) { 389 if (sendAs || sendObo){ 390 this._handleDelegateRights(user, sendAs, sendObo, true, true); 391 } 392 }; 393 394 ZmAccountsPage.prototype._handleAddDelegateButton = 395 function() { 396 var callback = this._grantDelegateRights.bind(this); 397 var dlg = this.getGrantRightsDlg(callback); 398 dlg.setData(); 399 dlg.popup(); 400 }; 401 402 403 ZmAccountsPage.prototype._editDelegateRights = 404 function() { 405 var user = this._editDelegateOrig.user; 406 var sendAs = arguments[1]; 407 var sendObo = arguments[2]; 408 var isGrant = null; 409 var updateSendAs = false; 410 var updateSendObo = false; 411 412 if (sendAs != this._editDelegateOrig.sendAs && sendObo != this._editDelegateOrig.sendOnBehalfOf){ 413 if (sendAs == sendObo){ 414 updateSendAs = updateSendObo = true; 415 isGrant = sendAs; 416 }else{ 417 this._handleDelegateRights(user, true, false, sendAs, false); 418 updateSendObo = true; 419 isGrant = sendObo; 420 } 421 }else if (sendAs != this._editDelegateOrig.sendAs){ 422 updateSendAs = true; 423 isGrant = sendAs; 424 }else if (sendObo != this._editDelegateOrig.sendOnBehalfOf){ 425 updateSendObo = true; 426 isGrant = sendObo; 427 } 428 this._handleDelegateRights(user, updateSendAs, updateSendObo, isGrant, true); 429 }; 430 431 ZmAccountsPage.prototype._editDelegateButton = 432 function() { 433 var item = this.delegatesList.getSelection()[0]; 434 this._editDelegateOrig = item; 435 this._editDelegateOrig.sendAs = item.sendAs || false; 436 this._editDelegateOrig.sendOnBehalfOf = item.sendOnBehalfOf || false; 437 var callback = this._editDelegateRights.bind(this); 438 var dlg = this.getGrantRightsDlg(callback); 439 dlg.setData(item); 440 dlg.popup(); 441 }; 442 ZmAccountsPage.prototype._compareDelegateEntries = 443 function(a, b) { 444 return a.user < b.user ? -1 : (a.user > b.user ? 1 : 0); 445 }; 446 ZmAccountsPage.prototype._setDelegateSendPrefs = 447 function(grants) { 448 var ace = grants._data.GetRightsResponse && grants._data.GetRightsResponse.ace; 449 var userRights = []; 450 var right = user = node = null; 451 var res = new AjxVector(); 452 if (!ace){ 453 this._dlSelectionListener(false); 454 return res; 455 } 456 for (var i=0;i<ace.length;i++){ 457 user = ace[i].d; 458 right = ace[i].right; 459 if (!userRights[user]){ 460 userRights[user] = {user:user, id:ace[i].zid}; 461 462 } 463 userRights[user][right] = true; 464 } 465 466 for (var usr in userRights) { 467 res.add(userRights[usr]) 468 } 469 470 res.sort(this._compareDelegateEntries); 471 return res; 472 }; 473 474 ZmAccountsPage.prototype._refreshRights = 475 function(grants) { 476 var delegatesEl = document.getElementById(this._htmlElId+"_DELEGATE_RIGHTS") || (this.delegatesList && this.delegatesList.getHtmlElement()); 477 var dlUsers = this._setDelegateSendPrefs(grants); 478 var delegatesList = new ZmAccountDelegatesListView(this); 479 delegatesList.replaceElement(delegatesEl); 480 delegatesList.setEnabled(true); 481 delegatesList.set(dlUsers); 482 delegatesList.addSelectionListener(this._dlSelectionListener.bind(this,(dlUsers.size() > 0))); 483 this.delegatesList = delegatesList; 484 if (this._grantRightsDlg && this._grantRightsDlg.isPoppedUp()) this._grantRightsDlg.popdown(); 485 486 this._dlSelectionListener(false); 487 }; 488 489 ZmAccountsPage.prototype._removeDelegateButton = 490 function() { 491 var item = this.delegatesList.getSelection()[0]; 492 this._handleDelegateRights(item.user, item.sendAs, item.sendOnBehalfOf, false, true); 493 }; 494 495 ZmAccountsPage.prototype._sendGrantRightsMessage = 496 function(granter, grantee, sendAs,sendObo,isGrant) { 497 var msg = new ZmMailMsg(); 498 var addrs = new AjxVector(); 499 var permissions = (sendAs && sendObo)?ZmMsg.sendAsAndSendOnBehalfOf:(sendAs?ZmMsg.sendAs:ZmMsg.sendOnBehalfOflbl); 500 var subject = ""; 501 var status = ""; 502 if (isGrant){ 503 status = (sendAs && sendObo) ? ZmMsg.delegateRightsStatus : ZmMsg.delegateRightStatus; 504 subject = (sendAs && sendObo) ? ZmMsg.delegateRightsSubject : ZmMsg.delegateRightSubject; 505 } else{ 506 status = (sendAs && sendObo) ? ZmMsg.revokeRightsStatus : ZmMsg.revokeRightStatus; 507 subject = (sendAs && sendObo) ? ZmMsg.revokeRightsSubject : ZmMsg.revokeRightSubject; 508 } 509 subject = AjxMessageFormat.format(subject, [granter]); 510 status = AjxMessageFormat.format(status, grantee); 511 var text = (isGrant)?ZmMsg.delegateCreatedText : ZmMsg.delegateRevokedText; 512 text = AjxMessageFormat.format(text, [permissions, grantee, granter]); 513 var html = (isGrant)?ZmMsg.delegateCreatedHtml : ZmMsg.delegateRevokedHtml; 514 html = AjxMessageFormat.format(html, [permissions, grantee, granter]); 515 appCtxt.setStatusMsg(status); 516 517 addrs.add(new AjxEmailAddress(grantee, AjxEmailAddress.TO)); 518 msg.setAddresses(AjxEmailAddress.TO, addrs); 519 msg.setSubject(subject); 520 var topPart = new ZmMimePart(); 521 topPart.setContentType(ZmMimeTable.MULTI_ALT); 522 523 var htmlPart = new ZmMimePart(); 524 htmlPart.setContentType(ZmMimeTable.TEXT_HTML); 525 htmlPart.setContent(html); 526 527 var textPart = new ZmMimePart(); 528 textPart.setContentType(ZmMimeTable.TEXT_PLAIN); 529 textPart.setContent(text); 530 531 topPart.children.add(textPart); 532 topPart.children.add(htmlPart); 533 msg.setTopPart(topPart); 534 msg.send(); 535 }; 536 537 ZmAccountsPage.getScratchCodes = 538 function(isNew, params, callback) { 539 if (isNew) { 540 var jsonObj = {GenerateScratchCodesRequest : {_jsns:"urn:zimbraAccount"}}; 541 } 542 else { 543 var jsonObj = {GetScratchCodesRequest: {_jsns: "urn:zimbraAccount"}}; 544 } 545 var getScratchCodesCallback = ZmAccountsPage._getScratchCodesCallback.bind(window, isNew, params, callback); 546 appCtxt.getAppController().sendRequest({jsonObj:jsonObj, asyncMode:true, callback:getScratchCodesCallback}); 547 }; 548 549 ZmAccountsPage._getScratchCodesCallback = 550 function(isNew, params, callback, result) { 551 if (!result || result.isException()) { 552 return; 553 } 554 var response = result.getResponse(); 555 var scratchCodesResponse = response && (response.GetScratchCodesResponse || response.GenerateScratchCodesResponse); 556 if (!scratchCodesResponse) { 557 return; 558 } 559 var scratchCode = scratchCodesResponse.scratchCodes && scratchCodesResponse.scratchCodes.scratchCode; 560 if (scratchCode) { 561 var scratchCodeArray = []; 562 for (var i = 0; i < scratchCode.length; i++) { 563 if (scratchCode[i]._content) { 564 scratchCodeArray.push(scratchCode[i]._content); 565 } 566 } 567 if (scratchCodeArray.length === 0) { 568 Dwt.setInnerHtml(params.twoStepAuthCodesSpan, ZmMsg.twoStepAuthOneTimeCodesEmpty); 569 Dwt.setDisplay(params.twoStepAuthCodesViewLink, Dwt.DISPLAY_NONE); 570 Dwt.setDisplay(params.twoStepAuthCodesGenerateLink, ""); 571 } 572 else { 573 Dwt.setInnerHtml(params.twoStepAuthCodesSpan, AjxMessageFormat.format(ZmMsg.twoStepAuthOneTimeCodesCount, scratchCodeArray.length)); 574 Dwt.setDisplay(params.twoStepAuthCodesViewLink, ""); 575 Dwt.setDisplay(params.twoStepAuthCodesGenerateLink, Dwt.DISPLAY_NONE); 576 } 577 if (callback) { 578 callback(scratchCodeArray); 579 } 580 } 581 }; 582 583 ZmAccountsPage.prototype._getTrustedDevicesCount = 584 function() { 585 var jsonObj = {GetTrustedDevicesRequest : {_jsns : "urn:zimbraAccount"}}; 586 var respCallback = this._getTrustedDevicesCountCallback.bind(this); 587 appCtxt.getAppController().sendRequest({jsonObj:jsonObj, asyncMode:true, callback:respCallback}); 588 }; 589 590 ZmAccountsPage.prototype._getTrustedDevicesCountCallback = 591 function(result) { 592 var response = result && result.getResponse(); 593 var getTrustedDevicesResponse = response && response.GetTrustedDevicesResponse; 594 if (!response || !getTrustedDevicesResponse) { 595 return; 596 } 597 var trustedDevicesCount = 0; 598 var trustedDeviceRevokeLink = document.getElementById(this._htmlElId + "_TRUSTED_DEVICE_REVOKE_LINK"); 599 if (getTrustedDevicesResponse.thisDeviceTrusted) { 600 if (trustedDeviceRevokeLink) { 601 Dwt.setHandler(trustedDeviceRevokeLink, DwtEvent.ONCLICK, this._handleTrustedDeviceRevokeLink.bind(this)); 602 Dwt.delClass(trustedDeviceRevokeLink, "ZmLinkDisabled"); 603 } 604 trustedDevicesCount = 1; 605 } 606 else { 607 if (trustedDeviceRevokeLink) { 608 Dwt.addClass(trustedDeviceRevokeLink, "ZmLinkDisabled"); 609 } 610 } 611 var trustedDevicesRevokeAllLink = document.getElementById(this._htmlElId + "_TRUSTED_DEVICES_REVOKE_ALL_LINK"); 612 if (getTrustedDevicesResponse.nOtherDevices) { 613 if (trustedDevicesRevokeAllLink) { 614 Dwt.setHandler(trustedDevicesRevokeAllLink, DwtEvent.ONCLICK, this._handleTrustedDevicesRevokeAllLink.bind(this)); 615 Dwt.delClass(trustedDevicesRevokeAllLink, "ZmLinkDisabled"); 616 } 617 trustedDevicesCount = trustedDevicesCount + parseInt(getTrustedDevicesResponse.nOtherDevices); 618 } 619 else { 620 if (trustedDevicesRevokeAllLink) { 621 Dwt.addClass(trustedDevicesRevokeAllLink, "ZmLinkDisabled"); 622 } 623 } 624 var trustedDevicesCountSpan = document.getElementById(this._htmlElId + "_TRUSTED_DEVICES_COUNT"); 625 Dwt.setInnerHtml(trustedDevicesCountSpan, AjxMessageFormat.format(ZmMsg.trustedDevicesCount, trustedDevicesCount)); 626 }; 627 628 ZmAccountsPage.prototype._handleTrustedDeviceRevokeLink = 629 function() { 630 var trustedDeviceRevokeLink = document.getElementById(this._htmlElId + "_TRUSTED_DEVICE_REVOKE_LINK"); 631 //link is currently disabled by CSS pointer-event which will prevent onclick event. For older browsers just check for ZmLinkDisabled class 632 if (Dwt.hasClass(trustedDeviceRevokeLink, "ZmLinkDisabled")) { 633 return false; 634 } 635 var msgDialog = appCtxt.getOkCancelMsgDialog(); 636 msgDialog.setMessage(ZmMsg.revokeTrustedDeviceMsg, DwtMessageDialog.WARNING_STYLE, ZmMsg.revokeTrustedDevice); 637 msgDialog.registerCallback(DwtDialog.OK_BUTTON, this._revokeTrustedDevice.bind(this, msgDialog)); 638 msgDialog.getButton(DwtDialog.OK_BUTTON).setText(ZmMsg.revoke); 639 msgDialog.popup(); 640 }; 641 642 ZmAccountsPage.prototype._revokeTrustedDevice = 643 function(msgDialog) { 644 msgDialog.popdown(); 645 var jsonObj = {RevokeTrustedDeviceRequest : {_jsns : "urn:zimbraAccount"}}; 646 var respCallback = this._revokeTrustedDeviceCallback.bind(this); 647 appCtxt.getAppController().sendRequest({jsonObj:jsonObj, asyncMode:true, callback:respCallback}); 648 }; 649 650 ZmAccountsPage.prototype._revokeTrustedDeviceCallback = 651 function() { 652 this._getTrustedDevicesCount(); 653 }; 654 655 ZmAccountsPage.prototype._handleTrustedDevicesRevokeAllLink = 656 function() { 657 var trustedDevicesRevokeAllLink = document.getElementById(this._htmlElId + "_TRUSTED_DEVICES_REVOKE_ALL_LINK"); 658 if (Dwt.hasClass(trustedDevicesRevokeAllLink, "ZmLinkDisabled")) { 659 return false; 660 } 661 var msgDialog = appCtxt.getOkCancelMsgDialog(); 662 msgDialog.setMessage(ZmMsg.revokeAllTrustedDevicesMsg, DwtMessageDialog.WARNING_STYLE, ZmMsg.revokeAllTrustedDevices); 663 msgDialog.registerCallback(DwtDialog.OK_BUTTON, this._revokeOtherTrustedDevices.bind(this, msgDialog)); 664 msgDialog.getButton(DwtDialog.OK_BUTTON).setText(ZmMsg.revokeAll); 665 msgDialog.popup(); 666 }; 667 668 ZmAccountsPage.prototype._revokeOtherTrustedDevices = 669 function(msgDialog) { 670 msgDialog.popdown(); 671 var jsonObj = {RevokeOtherTrustedDevicesRequest : {_jsns : "urn:zimbraAccount"}}; 672 var respCallback = this._revokeOtherTrustedDevicesCallback.bind(this); 673 appCtxt.getAppController().sendRequest({jsonObj:jsonObj, asyncMode:true, callback:respCallback}); 674 }; 675 676 ZmAccountsPage.prototype._revokeOtherTrustedDevicesCallback = 677 function() { 678 this._getTrustedDevicesCount(); 679 }; 680 681 ZmAccountsPage.prototype._getGrants = 682 function() { 683 var jsonObj = {GetRightsRequest:{ 684 _jsns:"urn:zimbraAccount", 685 "ace":[ 686 {right:ZmSetting.SEND_AS}, 687 {right:ZmSetting.SEND_ON_BEHALF_OF} 688 ] 689 } 690 }; 691 var respCallback = this._refreshRights.bind(this); 692 appCtxt.getAppController().sendRequest({jsonObj:jsonObj, asyncMode:true, callback:respCallback}); 693 }; 694 695 ZmAccountsPage.prototype._dlSelectionListener = 696 function(opt) { 697 this.editDelegateButton.setEnabled(opt); 698 this.removeDelegateButton.setEnabled(opt); 699 } 700 701 ZmAccountsPage.prototype.setAccountSecurity = 702 function() { 703 //If two-factor authentication feature is not available just return. 704 if (!appCtxt.get(ZmSetting.TWO_FACTOR_AUTH_AVAILABLE)) { 705 return; 706 } 707 //If two-factor authentication is required user cannot see the Enable/Disable two-step authentication link. 708 if (!appCtxt.get(ZmSetting.TWO_FACTOR_AUTH_REQUIRED)) { 709 var twoStepAuthLink = document.getElementById(this._htmlElId + "_TWO_STEP_AUTH_LINK"); 710 if (twoStepAuthLink) { 711 var paramsObj = { 712 twoStepAuthLink : twoStepAuthLink, 713 twoStepAuthSpan : Dwt.getElement(this._htmlElId + "_TWO_STEP_AUTH"), 714 twoStepAuthCodesContainer : Dwt.getElement(this._htmlElId + "_TWO_STEP_AUTH_CODES_CONTAINER"), 715 twoStepAuthEnabledCallback : this.setAccountSecurity.bind(this) 716 }; 717 Dwt.setHandler(twoStepAuthLink, DwtEvent.ONCLICK, this._handleTwoStepAuthLink.bind(this, paramsObj)); 718 } 719 } 720 //If two-factor authentication is not enabled just return. 721 if (!appCtxt.get(ZmSetting.TWO_FACTOR_AUTH_ENABLED)) { 722 return; 723 } 724 725 var twoStepAuthCodesSpan = document.getElementById(this._htmlElId + "_TWO_STEP_AUTH_CODES"); 726 if (twoStepAuthCodesSpan) { 727 var twoStepAuthCodesViewLink = document.getElementById(this._htmlElId + "_TWO_STEP_AUTH_CODES_VIEW_LINK"); 728 var twoStepAuthCodesGenerateLink = document.getElementById(this._htmlElId + "_TWO_STEP_AUTH_CODES_GENERATE_LINK"); 729 var params = { 730 twoStepAuthCodesSpan : twoStepAuthCodesSpan, 731 twoStepAuthCodesViewLink : twoStepAuthCodesViewLink, 732 twoStepAuthCodesGenerateLink : twoStepAuthCodesGenerateLink 733 }; 734 if (twoStepAuthCodesViewLink) { 735 Dwt.setHandler(twoStepAuthCodesViewLink, DwtEvent.ONCLICK, this._handleTwoStepAuthCodesViewLink.bind(this, params)); 736 } 737 if (twoStepAuthCodesGenerateLink) { 738 Dwt.setHandler(twoStepAuthCodesGenerateLink, DwtEvent.ONCLICK, ZmAccountsPage.getScratchCodes.bind(window, true, params, false)); 739 } 740 ZmAccountsPage.getScratchCodes(false, params, false); 741 } 742 743 if (appCtxt.get(ZmSetting.TRUSTED_DEVICES_ENABLED)) { 744 var trustedDevicesCountSpan = document.getElementById(this._htmlElId + "_TRUSTED_DEVICES_COUNT"); 745 if (trustedDevicesCountSpan) { 746 this._getTrustedDevicesCount(); 747 } 748 } 749 750 //Whether app-specific passwords are enabled when two-factor auth is enabled 751 if (appCtxt.get(ZmSetting.APP_PASSWORDS_ENABLED)) { 752 var applicationCodesElement = document.getElementById(this._htmlElId + "_APPLICATION_CODES"); 753 if (!applicationCodesElement) { 754 return; 755 } 756 this._getAppSpecificPasswords(applicationCodesElement); 757 758 var addApplicationCodeButton = document.getElementById(this._htmlElId + "_ADD_APPLICATION_CODE"); 759 if (addApplicationCodeButton) { 760 var button = new DwtButton({parent:this, id:"addApplicationCodeBtn"}); 761 button.setText(ZmMsg.twoStepAuthAddAppCode); 762 button.setEnabled(true); 763 button.addSelectionListener(new AjxListener(this, this._handleAddApplicationCode)); 764 button.replaceElement(addApplicationCodeButton); 765 this.addApplicationCodeButton = button; 766 } 767 768 var revokeApplicationCodeButton = document.getElementById(this._htmlElId+"_REVOKE_APPLICATION_CODE"); 769 if (revokeApplicationCodeButton) { 770 var button = new DwtButton({parent:this, id:"revokeApplicationCodeBtn"}); 771 button.setText(ZmMsg.twoStepAuthRevokeCode); 772 button.setEnabled(false); 773 button.addSelectionListener(new AjxListener(this, this._revokeApplicationCode)); 774 button.replaceElement(revokeApplicationCodeButton); 775 this.revokeApplicationCodeButton = button; 776 } 777 } 778 }; 779 780 ZmAccountsPage.prototype.setAccountDelegates = 781 function() { 782 var delegatesEl = document.getElementById(this._htmlElId+"_DELEGATE_RIGHTS"); 783 if(!delegatesEl) return; 784 this._getGrants(delegatesEl); 785 786 787 var addDelegateButtonDiv = document.getElementById(this._htmlElId+"_ADD_DELEGATE"); 788 if (addDelegateButtonDiv) { 789 var button = new DwtButton({parent:this, id:"addDelegateBtn"}); 790 button.setText(ZmMsg.addDelegate); 791 button.setEnabled(true); 792 button.addSelectionListener(new AjxListener(this, this._handleAddDelegateButton)); 793 button.replaceElement(addDelegateButtonDiv); 794 this.addDelegateButton = button; 795 } 796 797 var editDelegateButtonDiv = document.getElementById(this._htmlElId+"_EDIT_DELEGATE"); 798 if (editDelegateButtonDiv) { 799 var button = new DwtButton({parent:this, id:"editDelegateBtn"}); 800 button.setText(ZmMsg.editPermissions); 801 button.setEnabled(false); 802 button.addSelectionListener(new AjxListener(this, this._editDelegateButton)); 803 button.replaceElement(editDelegateButtonDiv); 804 this.editDelegateButton = button; 805 } 806 807 var removeDelegateButtonDiv = document.getElementById(this._htmlElId+"_REMOVE_DELEGATE"); 808 if (removeDelegateButtonDiv) { 809 var button = new DwtButton({parent:this, id:"removeDelegateBtn"}); 810 button.setText(ZmMsg.remove); 811 button.setEnabled(false); 812 button.addSelectionListener(new AjxListener(this, this._removeDelegateButton)); 813 button.replaceElement(removeDelegateButtonDiv); 814 this.removeDelegateButton = button; 815 } 816 817 818 819 } 820 // 821 // Public methods 822 // 823 824 ZmAccountsPage.prototype.setAccount = 825 function(account, skipUpdate, ignoreProvider) { 826 // keep track of changes made to current account 827 if (this._currentAccount) { 828 if (!skipUpdate) { 829 this._setAccountFields(this._currentAccount, this._currentSection); 830 } 831 this._tabGroup.removeMember(this._currentSection.tabGroup); 832 this._currentAccount = null; 833 this._currentSection = null; 834 } 835 836 // toggle delete button 837 if (this._deleteButton) { 838 var isEnabled = (appCtxt.isOffline) 839 ? (account && account.type == ZmAccount.TYPE_PERSONA) 840 : (account && account.type != ZmAccount.TYPE_ZIMBRA); 841 if (account.smtpEnabled) { 842 isEnabled = false; 843 } 844 this._deleteButton.setEnabled(isEnabled); 845 } 846 847 // intialize sections 848 for (var type in this._sectionDivs) { 849 Dwt.setVisible(this._sectionDivs[type], false); 850 } 851 852 // HACK: Attempt to get around an IE update issue. 853 setTimeout(AjxCallback.simpleClosure(this._setAccount2, this, account, skipUpdate, ignoreProvider),0); 854 }; 855 856 ZmAccountsPage.prototype._setAccount2 = 857 function(account, skipUpdate, ignoreProvider) { 858 // NOTE: hide all sections first, then show the specific section b/c some 859 // sections use same div. This avoids double inititalization in that case. 860 var isExternal = account instanceof ZmDataSource; 861 var provider = !ignoreProvider && isExternal && account.getProvider(); 862 var div = (provider && this._sectionDivs[provider.id]) || this._getSectionDiv(account); 863 if (div) { 864 this._currentAccount = account; 865 Dwt.setVisible(div, true); 866 if (appCtxt.isOffline) { 867 // bug 48014 - add "Use this persona" section for offline 868 if(account.type == ZmAccount.TYPE_PERSONA) { 869 this._currentSection = ZmAccountsPage.SECTIONS["PERSONA"]; 870 this._setPersona(account, this._currentSection); 871 } else { 872 this._currentSection = ZmAccountsPage.SECTIONS["PRIMARY"]; 873 this._setZimbraAccount(account, this._currentSection); 874 } 875 } else { 876 switch (account.type) { 877 case ZmAccount.TYPE_POP: 878 case ZmAccount.TYPE_IMAP: { 879 this._currentSection = provider && ZmAccountsPage.SECTIONS[provider.id]; 880 this._currentSection = this._currentSection || ZmAccountsPage.SECTIONS["EXTERNAL"]; 881 this._setExternalAccount(account, this._currentSection); 882 if (ignoreProvider) { 883 this._setControlValue("PROVIDER", this._currentSection, ""); 884 } 885 if (!skipUpdate) { 886 var password = this._getControlObject("PASSWORD", this._currentSection); 887 if (password) { 888 password.setShowPassword(false); 889 } 890 } 891 break; 892 } 893 case ZmAccount.TYPE_PERSONA: { 894 this._currentSection = ZmAccountsPage.SECTIONS["PERSONA"]; 895 this._setPersona(account, this._currentSection); 896 break; 897 } 898 default: { 899 this._currentSection = ZmAccountsPage.SECTIONS["PRIMARY"]; 900 this._setZimbraAccount(account, this._currentSection); 901 break; 902 } 903 } 904 } 905 if (!this._tabGroup.contains(this._currentSection.tabGroup)) { 906 this._tabGroup.addMember(this._currentSection.tabGroup); 907 } 908 } 909 910 // update list cells 911 this._updateList(account); 912 913 var control = this._currentSection && this._currentSection.controls[isExternal ? "EMAIL" : "NAME"]; 914 915 // When a hidden field is applied focus(), IE throw's an exception. 916 // Thus checking for isActive() 917 if (control && this.isActive()) { 918 control.focus(); 919 } 920 }; 921 922 ZmAccountsPage.prototype.isActive = 923 function() { 924 return (this._controller.getTabView().getActiveView().toString() == this.toString()); 925 }; 926 927 // ZmPreferencesPage methods 928 929 ZmAccountsPage.prototype.showMe = 930 function() { 931 var hasRendered = this.hasRendered; // cache before calling base 932 933 ZmPreferencesPage.prototype.showMe.apply(this, arguments); 934 935 if (!hasRendered) { 936 this.reset(); 937 } 938 }; 939 940 ZmAccountsPage.prototype.reset = 941 function(useDefaults) { 942 ZmPreferencesPage.prototype.reset.apply(this, arguments); 943 944 // clear current list of accounts 945 this._accounts.removeAll(); 946 this._deletedAccounts = []; 947 this._currentAccount = null; 948 this._currentSection = null; 949 950 var usedIdentities = {}; 951 952 // add zimbra accounts (i.e. family mboxes) 953 var mboxes = appCtxt.accountList.getAccounts(); 954 var active = appCtxt.getActiveAccount(); 955 for (var j in mboxes) { 956 var acct = mboxes[j]; 957 var ident = acct.getIdentity(); 958 // NOTE: We create proxies of all of the account objects so that we can 959 // store temporary values while editing. 960 if (active.isMain || acct == active) { 961 this._accounts.add(ZmAccountsPage.__createProxy(acct)); 962 if (ident) usedIdentities[ident.id] = true; 963 } 964 } 965 // add data sources unless we're in offline mode 966 if (!appCtxt.isOffline && active.isMain) { 967 var dataSourceCollection = appCtxt.getDataSourceCollection(); 968 var dataSources = dataSourceCollection.getItems(); // TODO: rename getItems or rename getIdentities 969 for (var i = 0; i < dataSources.length; i++) { 970 var datasource = dataSources[i]; 971 var ident = datasource.getIdentity(); 972 delete datasource.password; 973 this._accounts.add(ZmAccountsPage.__createProxy(datasource)); 974 if (ident) usedIdentities[ident.id] = true; 975 } 976 } 977 978 // add identities/personas 979 var identityCollection = appCtxt.getIdentityCollection(); 980 var identities = identityCollection.getIdentities(); 981 for (var i = 0; i < identities.length; i++) { 982 var identity = identities[i]; 983 if (identity.isDefault || identity.isFromDataSource) continue; 984 var id = identity.id; 985 if (usedIdentities[id]) continue; 986 usedIdentities[id] = true; 987 var persona = new ZmPersona(identity); 988 this._accounts.add(ZmAccountsPage.__createProxy(persona), null, true); 989 } 990 var signatureLinkElement = Dwt.getElement(this._htmlElId + "_External_Signatures_Link"); 991 Dwt.setHandler(signatureLinkElement, DwtEvent.ONCLICK, function(){skin.gotoPrefs("SIGNATURES")}); 992 // initialize list view 993 this._accounts.sort(ZmAccountsPage.__ACCOUNT_COMPARATOR); 994 var account = this._accounts.get(0); 995 this._resetAccountListView(account); 996 this.setAccount(account); 997 this.setAccountSecurity(); 998 this.setAccountDelegates(); 999 }; 1000 1001 // saving 1002 1003 ZmAccountsPage.prototype.isDirty = 1004 function() { 1005 // make sure that the current object proxy is up-to-date 1006 this._setAccountFields(this._currentAccount, this._currentSection, true); 1007 1008 var printAcct = function(acct) { 1009 if (AjxUtil.isArray(acct)) { 1010 return AjxUtil.map(acct, printAcct).join("\n"); 1011 } 1012 return ["name: ",acct.name,", id: ",acct.id].join(""); 1013 } 1014 1015 var dirty = this._deletedAccounts.length > 0; 1016 if (dirty) { 1017 AjxDebug.println(AjxDebug.PREFS, "Dirty preferences:\n" + "Deleted accounts:\n" + printAcct(this._deletedAccounts)); 1018 } 1019 if (!dirty) { 1020 var accounts = this._accounts.getArray(); 1021 var dirtyAccounts = []; 1022 for (var i = 0; i < accounts.length; i++) { 1023 var account = accounts[i]; 1024 if (account._new || account._dirty || account._visibleDirty) { 1025 dirty = true; 1026 dirtyAccounts.push(account); 1027 } 1028 } 1029 if (dirty) { 1030 AjxDebug.println(AjxDebug.PREFS, "Dirty preferences:\n" + "Dirty accounts:\n" + printAcct(dirtyAccounts)); 1031 } 1032 } 1033 return dirty; 1034 }; 1035 1036 /** 1037 * Does minimal checking: 1038 * <li>bug 21104: persona name and the associated display value for the From address 1039 * <li>bug 950: email addresses 1040 */ 1041 ZmAccountsPage.prototype.validate = 1042 function() { 1043 var accounts = this._accounts.getArray(); 1044 for (var i = 0; i < accounts.length; i++) { 1045 var account = accounts[i]; 1046 var type = account.type; 1047 var isPrimary = type == ZmAccount.TYPE_ZIMBRA; 1048 var isExternal = type == ZmAccount.TYPE_POP || type == ZmAccount.TYPE_IMAP; 1049 var isPersona = type == ZmAccount.TYPE_PERSONA; 1050 1051 // bug 21104 1052 if (isPersona && (account._new || account._dirty) && 1053 !(account.identity && account.identity.name)) { 1054 this._errorMsg = ZmMsg.invalidPersonaName; 1055 return false; 1056 } 1057 // bug 950 1058 if (isExternal && !this.__validateEmail(this.__getAccountValue(account, "EMAIL"))) { 1059 return false; 1060 } 1061 if (this.__getIdentityValue(account, "REPLY_TO") && 1062 !this.__validateEmail(this.__getIdentityValue(account, "REPLY_TO_EMAIL"))) { 1063 return false; 1064 } 1065 if (isExternal && !this.__validateEmail(this.__getIdentityValue(account, "FROM_EMAIL"))) { 1066 return false; 1067 } 1068 if (isPersona && this.__getIdentityValue(account, "WHEN_SENT_TO") && 1069 !this.__validateEmailList(this.__getIdentityValue(account, "WHEN_SENT_TO_LIST"))) { 1070 return false; 1071 } 1072 if ( AjxUtil.isEmpty(this.__getIdentityValue(account, "FROM_NAME")) && 1073 !AjxUtil.isEmpty(appCtxt.get(ZmSetting.DISPLAY_NAME))) { 1074 this._errorMsg = ZmMsg.missingEmailDisplayName; 1075 return false; 1076 } 1077 } 1078 return true; 1079 }; 1080 1081 ZmAccountsPage.prototype.__getAccountValue = 1082 function(account, id) { 1083 var prop = ZmAccountsPage.ACCOUNT_PROPS[id]; 1084 if (!prop) return; 1085 return (typeof prop == "string") ? account[prop] : account[prop.getter](); 1086 }; 1087 1088 ZmAccountsPage.prototype.__getIdentityValue = 1089 function(account, id) { 1090 var prop = ZmAccountsPage.IDENTITY_PROPS[id]; 1091 if (!prop) return; 1092 var identity = account.getIdentity(); 1093 return identity && (typeof prop == "string" ? identity[prop] : identity[prop]()); 1094 }; 1095 1096 ZmAccountsPage.prototype.__validateEmail = 1097 function(s) { 1098 if (!ZmPref.validateEmail(s)) { 1099 this._errorMsg = AjxStringUtil.htmlEncode(AjxMessageFormat.format(ZmMsg.invalidEmail, [s])); 1100 return false; 1101 } 1102 return true; 1103 }; 1104 1105 ZmAccountsPage.prototype.__validateEmailList = 1106 function(l) { 1107 var ss = String(l).split(/[,;]/); 1108 for (var i = 0; i < ss.length; i++) { 1109 var valid = this.__validateEmail(ss[i]); 1110 if (!valid) return false; 1111 } 1112 return true; 1113 }; 1114 1115 ZmAccountsPage.prototype.getErrorMessage = 1116 function() { 1117 return this._errorMsg; 1118 }; 1119 1120 ZmAccountsPage.prototype.getPreSaveCallback = 1121 function() { 1122 return new AjxCallback(this, this._preSave); 1123 }; 1124 1125 ZmAccountsPage.prototype.getPostSaveCallback = 1126 function() { 1127 return new AjxCallback(this, this._postSave); 1128 }; 1129 1130 ZmAccountsPage.prototype.addCommand = 1131 function(batchCmd) { 1132 // make sure that the current object proxy is up-to-date 1133 // NOTE: This is already done so don't do it again or else we'll 1134 // NOTE: lose the folderId from the create/rename folder op. 1135 //this._setAccountFields(this._currentAccount, this._currentSection); 1136 1137 // delete accounts 1138 for (var i = 0; i < this._deletedAccounts.length; i++) { 1139 var callback = null; 1140 var account = this._deletedAccounts[i]; 1141 var folderId = account.folderId; 1142 if (folderId == ZmAccountsPage.DOWNLOAD_TO_FOLDER || folderId != ZmAccountsPage.DOWNLOAD_TO_INBOX) { 1143 var root = appCtxt.getById(ZmOrganizer.ID_ROOT); 1144 var name = account.getName(); 1145 var folder = root.getByName(name); 1146 if (folder && !folder.isSystem()) { 1147 callback = new AjxCallback(this, this._promptToDeleteFolder, [folder]); 1148 } 1149 } 1150 this._deletedAccounts[i].doDelete(callback, null, batchCmd); 1151 } 1152 1153 // for multi-account mbox, check if user changed visible flag on subaccounts 1154 if (appCtxt.accountList.size(true) > 1) { 1155 this._saveVisibleAccounts(batchCmd); 1156 } 1157 1158 // modify existing accounts 1159 var newAccounts = []; 1160 var accounts = this._accounts.getArray(); 1161 for (var i = 0; i < accounts.length; i++) { 1162 var account = accounts[i]; 1163 if (account._new) { 1164 newAccounts.push(account); 1165 continue; 1166 } 1167 1168 if (account._dirty) { 1169 var callback = new AjxCallback(this, this._handleSaveAccount, [account]); 1170 account.save(callback, null, batchCmd); 1171 } 1172 } 1173 1174 // add new accounts 1175 for (var i = 0; i < newAccounts.length; i++) { 1176 var account = newAccounts[i]; 1177 var callback = new AjxCallback(this, this._handleCreateAccount, [account]); 1178 account.create(callback, null, batchCmd); 1179 } 1180 1181 // refresh display after all is done 1182 var soapDoc = AjxSoapDoc.create("NoOpRequest", "urn:zimbraMail"); 1183 var callback = new AjxCallback(this, this.reset); 1184 batchCmd.addNewRequestParams(soapDoc, callback); 1185 }; 1186 1187 // 1188 // Protected methods 1189 // 1190 1191 ZmAccountsPage.prototype._testAccounts = 1192 function(accounts, okCallback, cancelCallback) { 1193 this._controller.getTestDialog().popup(accounts, okCallback, cancelCallback); 1194 }; 1195 1196 // set controls based on account 1197 1198 ZmAccountsPage.prototype._setZimbraAccount = 1199 function(account, section) { 1200 this._setGenericFields(account, section); 1201 this._setIdentityFields(account, section); 1202 if (appCtxt.isFamilyMbox) { 1203 this._setControlEnabled("VISIBLE", section, !account.isMain); 1204 } 1205 }; 1206 1207 ZmAccountsPage.prototype._setExternalAccount = 1208 function(account, section) { 1209 this._setGenericFields(account, section); 1210 this._setDataSourceFields(account, section); 1211 this._setIdentityFields(account, section); 1212 if (this._setControlVisible("ALERT", section, !account.isStatusOk())) { 1213 var alert = section.controls["ALERT"]; 1214 alert.setStyle(DwtAlert.CRITICAL); 1215 alert.setTitle(account.failingSince ? ZmMsg.dataSourceFailureTitle : ZmMsg.accountInactiveTitle); 1216 alert.setContent(account.lastError || ZmMsg.accountInactiveContent); 1217 } 1218 }; 1219 1220 ZmAccountsPage.prototype._setPersona = 1221 function(account, section) { 1222 this._setGenericFields(account, section); 1223 this._setIdentityFields(account, section); 1224 }; 1225 1226 ZmAccountsPage.prototype._setGenericFields = 1227 function(account, section) { 1228 this._setControlValue("NAME", section, account.getName()); 1229 this._setControlValue("HEADER", section, account.getName()); 1230 this._setControlValue("EMAIL", section, account.getEmail()); 1231 this._setControlValue("VISIBLE", section, account.visible); 1232 }; 1233 1234 ZmAccountsPage.prototype._setDataSourceFields = 1235 function(account, section) { 1236 var isSsl = account.connectionType == ZmDataSource.CONNECT_SSL; 1237 var isInbox = account.folderId == ZmOrganizer.ID_INBOX; 1238 var isPortChanged = account.port != account.getDefaultPort(); 1239 var isSmtpEnabled = account.smtpEnabled; 1240 1241 this._setControlValue("ACCOUNT_TYPE", section, account.type); 1242 this._setControlEnabled("ACCOUNT_TYPE", section, account._new); 1243 this._setControlValue("USERNAME", section, account.userName); 1244 this._setControlValue("HOST", section, account.mailServer); 1245 this._setControlValue("PASSWORD", section, account.password); 1246 this._setControlValue("SSL", section, isSsl); 1247 this._setControlEnabled("TEST", section, true); 1248 this._setDownloadToFolder(account); 1249 this._setControlValue("DELETE_AFTER_DOWNLOAD", section, account.leaveOnServer); 1250 this._setControlValue("CHANGE_PORT", section, isPortChanged); 1251 this._setControlEnabled("PORT", section, isPortChanged); 1252 this._setPortControls(account.type, account.connectionType, account.port); 1253 1254 var provider = account.getProvider(); 1255 this._setControlValue("PROVIDER", section, provider ? provider.id : ""); 1256 this._setControlVisible("PROVIDER", section, AjxUtil.keys(ZmDataSource.getProviders()).length > 0); 1257 this._setExternalSectionControlsView(section, !isSmtpEnabled); 1258 }; 1259 1260 ZmAccountsPage.prototype._setDownloadToFolder = 1261 function(account) { 1262 var section = this._currentSection; 1263 var radioGroup = section.controls["DOWNLOAD_TO"]; 1264 if (!radioGroup) return; 1265 1266 var pref = ZmAccountsPage.PREFS["DOWNLOAD_TO"]; 1267 var options = pref.options; 1268 var displayOptions = pref.displayOptions; 1269 var pattern = displayOptions[options[0] == ZmAccountsPage.DOWNLOAD_TO_INBOX ? 1 : 0]; 1270 var name = AjxStringUtil.htmlEncode(this._getControlValue("NAME", section)); 1271 var text = AjxMessageFormat.format(pattern, name); 1272 1273 var radioButton = radioGroup.getRadioButtonByValue(ZmAccountsPage.DOWNLOAD_TO_FOLDER); 1274 radioButton.setText(text); 1275 1276 var isImap = account.type == ZmAccount.TYPE_IMAP; 1277 var isInbox = !isImap && account.folderId == ZmOrganizer.ID_INBOX; 1278 var value = isInbox ? ZmAccountsPage.DOWNLOAD_TO_INBOX : ZmAccountsPage.DOWNLOAD_TO_FOLDER; 1279 this._setControlValue("DOWNLOAD_TO", section, value); 1280 this._setControlEnabled("DOWNLOAD_TO", section, !isImap); 1281 }; 1282 1283 ZmAccountsPage.prototype._setPortControls = 1284 function(accountType, connectionType, accountPort) { 1285 var isPop = accountType == ZmAccount.TYPE_POP; 1286 var isSsl = connectionType == ZmDataSource.CONNECT_SSL; 1287 1288 var section = this._currentSection; 1289 this._setControlValue("PORT", section, accountPort); 1290 this._setControlEnabled("DELETE_AFTER_DOWNLOAD", section, isPop); 1291 1292 this._setControlEnabled("DOWNLOAD_TO", section, isPop); 1293 // imap is never allowed in inbox 1294 if (!isPop) { 1295 this._setControlValue("DOWNLOAD_TO", section, ZmAccountsPage.DOWNLOAD_TO_FOLDER); 1296 } 1297 1298 var portTypeLabel = AjxMessageFormat.format(ZmAccountsPage.PREFS["CHANGE_PORT"].displayName, accountType); 1299 this._setControlLabel("CHANGE_PORT", section, portTypeLabel); 1300 1301 var defaultPort = isPop ? ZmPopAccount.PORT_CLEAR : ZmImapAccount.PORT_CLEAR; 1302 if (isSsl) { 1303 defaultPort = isPop ? ZmPopAccount.PORT_SSL : ZmImapAccount.PORT_SSL; 1304 } 1305 var defaultPortLabel = AjxMessageFormat.format(ZmAccountsPage.PREFS["PORT_DEFAULT"].displayName, defaultPort); 1306 this._setControlLabel("PORT_DEFAULT", section, defaultPortLabel); 1307 }; 1308 1309 ZmAccountsPage.prototype._setIdentityFields = 1310 function(account, section) { 1311 var identity = account.getIdentity(); 1312 1313 this._setControlValue("FROM_NAME", section, identity.sendFromDisplay); 1314 this._setControlValue("FROM_EMAIL", section, (identity.sendFromAddressType == ZmSetting.SEND_ON_BEHALF_OF) ? ZmMsg.onBehalfOfMidLabel + " " + identity.sendFromAddress : identity.sendFromAddress); 1315 this._setControlValue("FROM_EMAIL_TYPE", section, identity.sendFromAddressType); 1316 this._setControlValue("REPLY_TO", section, identity.setReplyTo); 1317 this._setControlValue("REPLY_TO_NAME", section, identity.setReplyToDisplay); 1318 this._setControlValue("REPLY_TO_EMAIL", section, identity.setReplyToAddress); 1319 this._setControlValue("READ_RECEIPT_TO_ADDR", section, identity.readReceiptAddr); 1320 this._setControlValue("WHEN_SENT_TO", section, identity.useWhenSentTo); 1321 this._setControlValue("WHEN_SENT_TO_LIST", section, identity.whenSentToAddresses); 1322 this._setControlValue("WHEN_IN_FOLDER", section, identity.useWhenInFolder); 1323 this._setControlValue("WHEN_IN_FOLDER_LIST", section, identity.whenInFolderIds); 1324 1325 this._setReplyToControls(); 1326 this._setWhenSentToControls(); 1327 this._setWhenInFolderControls(); 1328 }; 1329 1330 ZmAccountsPage.prototype._saveVisibleAccounts = 1331 function(batchCmd) { 1332 var accounts = this._accounts.getArray(); 1333 var visibilityChanged = false; 1334 1335 // check if visibility changed for any sub accounts 1336 for (var i = 0; i < accounts.length; i++) { 1337 if (accounts[i]._visibleDirty) { 1338 visibilityChanged = true; 1339 break; 1340 } 1341 } 1342 1343 // collect *all* visible accounts for ModifyPrefsRequest and add to batchCmd 1344 if (visibilityChanged) { 1345 var soapDoc = AjxSoapDoc.create("ModifyPrefsRequest", "urn:zimbraAccount"); 1346 var setting = appCtxt.getSettings().getSetting(ZmSetting.CHILD_ACCTS_VISIBLE); 1347 var foundVisible = false; 1348 for (var j = 0; j < accounts.length; j++) { 1349 var account = accounts[j]; 1350 if (!account.isMain && account.visible) { 1351 var node = soapDoc.set("pref", account.id); 1352 node.setAttribute("name", setting.name); 1353 foundVisible = true; 1354 } 1355 } 1356 // user unset visible for all accounts - send empty value 1357 if (!foundVisible) { 1358 var node = soapDoc.set("pref", ""); 1359 node.setAttribute("name", setting.name); 1360 } 1361 var callback = new AjxCallback(this, this._handleSaveVisibleAccount); 1362 batchCmd.addNewRequestParams(soapDoc, callback); 1363 } 1364 }; 1365 1366 ZmAccountsPage.prototype._setReplyToControls = 1367 function() { 1368 var section = this._currentSection; 1369 var replyTo = this._getControlValue("REPLY_TO", section); 1370 1371 this._setControlEnabled("REPLY_TO_NAME", section, replyTo); 1372 this._setControlEnabled("REPLY_TO_EMAIL", section, replyTo); 1373 }; 1374 1375 ZmAccountsPage.prototype._setWhenSentToControls = 1376 function() { 1377 var section = this._currentSection; 1378 var whenSentTo = this._getControlValue("WHEN_SENT_TO", section); 1379 1380 this._setControlEnabled("WHEN_SENT_TO_LIST", section, whenSentTo); 1381 }; 1382 1383 ZmAccountsPage.prototype._setWhenInFolderControls = 1384 function() { 1385 var section = this._currentSection; 1386 var whenInFolder = this._getControlValue("WHEN_IN_FOLDER", section); 1387 1388 this._setControlEnabled("WHEN_IN_FOLDER_LIST", section, whenInFolder); 1389 this._setControlEnabled("WHEN_IN_FOLDER_BUTTON", section, whenInFolder); 1390 }; 1391 1392 ZmAccountsPage.prototype._setControlLabel = 1393 function(id, section, value) { 1394 var control = section.controls[id]; 1395 var setup = ZmAccountsPage.PREFS[id]; 1396 if (!control || !setup) return; 1397 1398 switch (setup.displayContainer) { 1399 case ZmPref.TYPE_STATIC: 1400 case ZmPref.TYPE_CHECKBOX: { 1401 control.setText(value); 1402 break; 1403 } 1404 } 1405 }; 1406 1407 ZmAccountsPage.prototype._getControlObject = 1408 function(id, section) { 1409 return section && section.controls[id]; 1410 }; 1411 1412 ZmAccountsPage.prototype._setControlValue = 1413 function(id, section, value) { 1414 var control = section.controls[id]; 1415 var setup = ZmAccountsPage.PREFS[id]; 1416 if (!setup) return; 1417 if (!control) { 1418 setup.value = value; 1419 return; 1420 } 1421 1422 if (setup.displayFunction) { 1423 value = setup.displayFunction(value); 1424 } 1425 if (id == "DELETE_AFTER_DOWNLOAD") { 1426 value = !value; 1427 } 1428 else if (id == "WHEN_SENT_TO_LIST") { 1429 value = value ? value.join(", ") : ""; 1430 } 1431 else if (id == "WHEN_IN_FOLDER_LIST") { 1432 var tree = appCtxt.getTree(ZmOrganizer.FOLDER); 1433 var folderIds = value; 1434 var array = [value]; 1435 var seenComma = false; 1436 for (var i = 0; i < folderIds.length; i++) { 1437 var fid = folderIds[i]; 1438 var searchPath = array[i] = tree.getById(fid).getSearchPath(); 1439 seenComma = seenComma || searchPath.match(/,/); 1440 } 1441 value = AjxUtil.uniq(array).join(seenComma ? "; " : ", "); 1442 } 1443 1444 switch (setup.displayContainer) { 1445 case ZmPref.TYPE_STATIC: { 1446 var message = setup.displayName ? AjxMessageFormat.format(setup.displayName, value) : value; 1447 control.setText(message); 1448 break; 1449 } 1450 case ZmPref.TYPE_CHECKBOX: { 1451 control.setSelected(value); 1452 break; 1453 } 1454 case ZmPref.TYPE_INPUT: 1455 case ZmPref.TYPE_COMBOBOX: { 1456 control.setValue(value); 1457 break; 1458 } 1459 case ZmPref.TYPE_SELECT: 1460 case ZmPref.TYPE_RADIO_GROUP: { 1461 control.setSelectedValue(value, true); 1462 break; 1463 } 1464 } 1465 }; 1466 1467 ZmAccountsPage.prototype._getControlValue = 1468 function(id, section) { 1469 var control = section.controls[id]; 1470 var setup = ZmAccountsPage.PREFS[id]; 1471 if (!setup) return null; 1472 if (!control) { 1473 return setup.value || (id == "DOWNLOAD_TO" && ZmAccountsPage.DOWNLOAD_TO_FOLDER); 1474 } 1475 1476 var value = null; 1477 if (id == "WHEN_SENT_TO_LIST") { 1478 var array = AjxEmailAddress.parseEmailString(control.getValue()).all.getArray(); 1479 for (var i = 0; i < array.length; i++) { 1480 array[i] = array[i].address; 1481 } 1482 value = array; 1483 } 1484 else if (id == "WHEN_IN_FOLDER_LIST") { 1485 var tree = appCtxt.getTree(ZmOrganizer.FOLDER); 1486 var root = tree.getById(ZmOrganizer.ID_ROOT); 1487 1488 var folderPaths = control.getValue().replace(/\s*(;|,)\s*/g,"$1").split(/;|,/); 1489 var array = []; 1490 for (var i = 0; i < folderPaths.length; i++) { 1491 var folder = root.getByPath(folderPaths[i],true); 1492 if (!folder) continue; 1493 array.push(folder.id); 1494 } 1495 value = array; 1496 } 1497 else if (id == "DELETE_AFTER_DOWNLOAD") { 1498 value = !control.isSelected(); 1499 } 1500 else { 1501 switch (setup.displayContainer) { 1502 case ZmPref.TYPE_STATIC: { 1503 value = control.getText(); 1504 break; 1505 } 1506 case ZmPref.TYPE_CHECKBOX: { 1507 value = control.isSelected(); 1508 if (setup.options) { 1509 value = setup.options[Number(value)]; 1510 } 1511 break; 1512 } 1513 case ZmPref.TYPE_RADIO_GROUP: { 1514 value = control.getSelectedValue(); 1515 break; 1516 } 1517 case ZmPref.TYPE_INPUT: 1518 case ZmPref.TYPE_SELECT: { 1519 value = control.getValue(); 1520 break; 1521 } 1522 case ZmPref.TYPE_COMBOBOX: { 1523 value = control.getValue() || control.getText(); 1524 break; 1525 } 1526 } 1527 } 1528 1529 return setup.valueFunction ? setup.valueFunction(value) : value; 1530 }; 1531 1532 ZmAccountsPage.prototype._setControlVisible = 1533 function(id, section, visible) { 1534 var control = section.controls[id]; 1535 var setup = ZmAccountsPage.PREFS[id]; 1536 if (control) control.setVisible(visible); 1537 var el = document.getElementById([this._htmlElId, section.id, id, "row"].join("_")); 1538 if (el) Dwt.setVisible(el, visible); 1539 return control || el ? visible : false; 1540 }; 1541 1542 ZmAccountsPage.prototype._setControlEnabled = 1543 function(id, section, enabled) { 1544 var control = section.controls[id]; 1545 var setup = ZmAccountsPage.PREFS[id]; 1546 if (!control || !setup) return; 1547 1548 control.setEnabled(enabled); 1549 }; 1550 1551 /** 1552 * If selected datasource has attr smtpEnabled to true, make the external controls 1553 * readOnly else editable. 1554 */ 1555 1556 ZmAccountsPage.prototype._setExternalSectionControlsView = 1557 function(section, toEnable) { 1558 var prefs, 1559 prefsLen, 1560 i, 1561 pref, 1562 signatureLinkElement, 1563 signatureTextSpan; 1564 1565 prefs = section.prefs; // external sections prefs. 1566 prefsLen = prefs.length; 1567 signatureLinkElement = Dwt.getElement(this._htmlElId + "_External_Signatures_Link"); 1568 signatureTextSpan = Dwt.getElement(this._htmlElId + "_External_Signatures_Text"); 1569 1570 for (i = 0; i < prefsLen; i++) { 1571 pref = prefs[i]; 1572 this._setControlEnabled(pref, section, toEnable); // Disable/enable external section pref, depending on the boolean value of attr smtpEnabled in selected Data Source. 1573 } 1574 if (toEnable) { 1575 Dwt.setVisible(signatureLinkElement,true); 1576 Dwt.setVisible(signatureTextSpan,false); 1577 } 1578 else { 1579 Dwt.setVisible(signatureLinkElement,false); 1580 Dwt.setVisible(signatureTextSpan,true); 1581 } 1582 }; 1583 1584 ZmAccountsPage.prototype._setAccountFields = 1585 function(account, section, dontClearFolder) { 1586 if (!account || !section) return; 1587 1588 for (var id in ZmAccountsPage.ACCOUNT_PROPS) { 1589 var control = section.controls[id]; 1590 if (!control) { 1591 // HACK: default to new folder if control not available 1592 if (id == "DOWNLOAD_TO" && !dontClearFolder) { 1593 account.folderId = ZmAccountsPage.DOWNLOAD_TO_FOLDER; 1594 } 1595 continue; 1596 } 1597 1598 var prop = ZmAccountsPage.ACCOUNT_PROPS[id]; 1599 var isField = AjxUtil.isString(prop); 1600 1601 var ovalue = isField ? account[prop] : account[prop.getter](); 1602 var nvalue = this._getControlValue(id, section); 1603 if (this._valuesEqual(ovalue, nvalue)) continue; 1604 1605 // special case: download-to 1606 if (id == "DOWNLOAD_TO" && 1607 ovalue != ZmOrganizer.ID_INBOX && nvalue != ZmOrganizer.ID_INBOX) { 1608 continue; 1609 } 1610 1611 // handling visible is special 1612 if (id == "VISIBLE") { 1613 account._visibleDirty = true; 1614 } else { 1615 account._dirty = true; 1616 } 1617 1618 if (AjxUtil.isString(prop)) { 1619 account[prop] = nvalue; 1620 } 1621 else { 1622 account[prop.setter](nvalue); 1623 } 1624 } 1625 1626 var identity = account.getIdentity(); 1627 for (var id in ZmAccountsPage.IDENTITY_PROPS) { 1628 var control = section.controls[id]; 1629 if (!control) { continue; } 1630 1631 var prop = ZmAccountsPage.IDENTITY_PROPS[id]; 1632 var isField = AjxUtil.isString(prop); 1633 1634 var ovalue = (isField ? identity[prop] : identity[prop.getter]())|| ""; 1635 var nvalue = (this._getControlValue(id, section))||""; 1636 if (id == "FROM_EMAIL" && identity.sendFromAddressType == ZmSetting.SEND_ON_BEHALF_OF) ovalue = ZmMsg.sendOnBehalfOf + " " + ovalue; 1637 1638 if (this._valuesEqual(ovalue, nvalue)) { continue; } 1639 1640 if (id == "FROM_EMAIL" && nvalue.indexOf(ZmMsg.sendOnBehalfOf + " ") == 0) { 1641 nvalue = nvalue.replace(ZmMsg.sendOnBehalfOf + " ", ""); 1642 identity.sendFromAddressType = ZmSetting.SEND_ON_BEHALF_OF; 1643 } else { 1644 identity.sendFromAddressType = ZmSetting.SEND_AS; 1645 } 1646 1647 account._dirty = true; 1648 if (isField) { 1649 identity[prop] = nvalue; 1650 } 1651 else { 1652 identity[prop.setter](nvalue); 1653 } 1654 } 1655 }; 1656 1657 ZmAccountsPage.prototype._valuesEqual = 1658 function(ovalue, nvalue) { 1659 if (AjxUtil.isArray(ovalue) && AjxUtil.isArray(nvalue)) { 1660 if (ovalue.length != nvalue.length) { 1661 return false; 1662 } 1663 var oarray = [].concat(ovalue).sort(); 1664 var narray = [].concat(nvalue).sort(); 1665 for (var i = 0; i < oarray.length; i++) { 1666 if (oarray[i] != narray[i]) { 1667 return false; 1668 } 1669 } 1670 return true; 1671 } 1672 return ovalue == nvalue; 1673 }; 1674 1675 // init ui 1676 1677 ZmAccountsPage.prototype._initControl = 1678 function(id, setup, value, section) { 1679 ZmPreferencesPage.prototype._initControl.apply(this, arguments); 1680 if (id == "PROVIDER" && !setup.options) { 1681 var providers = AjxUtil.values(ZmDataSource.getProviders()); 1682 providers.sort(ZmAccountsPage.__BY_PROVIDER_NAME); 1683 providers.unshift( { id: "", name: "Custom" } ); // TODO: i18n 1684 1685 var options = new Array(providers.length); 1686 var displayOptions = new Array(providers.length); 1687 for (var i = 0; i < providers.length; i++) { 1688 var provider = providers[i]; 1689 options[i] = provider.id; 1690 displayOptions[i] = provider.name; 1691 } 1692 1693 setup.options = options; 1694 setup.displayOptions = displayOptions; 1695 } 1696 }; 1697 1698 ZmAccountsPage.prototype._setupInput = 1699 function(id, setup, value) { 1700 if (id == "PASSWORD") { 1701 var input = new DwtPasswordField({ parent: this }); 1702 input.setValue(value); 1703 this.setFormObject(id, input); 1704 return input; 1705 } 1706 var input = ZmPreferencesPage.prototype._setupInput.apply(this, arguments); 1707 switch (id) { 1708 case "NAME": { 1709 input.addListener(DwtEvent.ONKEYUP, new AjxListener(this, this._handleNameChange)); 1710 break; 1711 } 1712 case "HOST": { 1713 input.addListener(DwtEvent.ONKEYUP, new AjxListener(this, this._handleHostChange)); 1714 break; 1715 } 1716 case "EMAIL": { 1717 input.addListener(DwtEvent.ONKEYUP, new AjxListener(this, this._handleEmailChange)); 1718 break; 1719 } 1720 case "USERNAME": { 1721 input.addListener(DwtEvent.ONKEYUP, new AjxListener(this, this._handleUserNameChange)); 1722 break; 1723 } 1724 case "WHEN_SENT_TO_LIST": { 1725 input.setHint(appCtxt.get(ZmSetting.USERNAME)); 1726 break; 1727 } 1728 } 1729 return input; 1730 }; 1731 1732 ZmAccountsPage.prototype._setupCheckbox = 1733 function(id, setup, value) { 1734 var checkbox = ZmPreferencesPage.prototype._setupCheckbox.apply(this, arguments); 1735 if (id == "SSL") { 1736 checkbox.addSelectionListener(new AjxListener(this, this._handleTypeOrSslChange)); 1737 } 1738 else if (id == "CHANGE_PORT") { 1739 checkbox.addSelectionListener(new AjxListener(this, this._handleChangePort)); 1740 } 1741 else if (id == "REPLY_TO") { 1742 checkbox.addSelectionListener(new AjxListener(this, this._handleReplyTo)); 1743 } 1744 else if (id == "WHEN_SENT_TO") { 1745 checkbox.addSelectionListener(new AjxListener(this, this._handleWhenSentTo)); 1746 } 1747 else if (id == "WHEN_IN_FOLDER") { 1748 checkbox.addSelectionListener(new AjxListener(this, this._handleWhenInFolder)); 1749 } 1750 return checkbox; 1751 }; 1752 1753 ZmAccountsPage.prototype._setupRadioGroup = 1754 function(id, setup, value) { 1755 var container = ZmPreferencesPage.prototype._setupRadioGroup.apply(this, arguments); 1756 if (id == "ACCOUNT_TYPE") { 1757 var radioGroup = this.getFormObject("ACCOUNT_TYPE"); 1758 radioGroup.addSelectionListener(new AjxListener(this, this._handleTypeChange)); 1759 } 1760 return container; 1761 }; 1762 1763 ZmAccountsPage.prototype._setSelectFromLabels = 1764 function( displayOptions, fromAddress){ 1765 if (!this._selectFromLabels){ 1766 var tmpArray1 = []; 1767 var tmpArray2 = []; 1768 var email = null; 1769 var index = -1; 1770 // Add sendOnBehalfOf emails 1771 for (var i=0;i < appCtxt.sendOboEmails.length; i++){ 1772 email = appCtxt.sendOboEmails[i].addr; 1773 index = -1; 1774 if (index = AjxUtil.indexOf(fromAddress,email) != -1) 1775 fromAddress.splice(index, 1); 1776 if (index = AjxUtil.indexOf(displayOptions,email) != -1) 1777 displayOptions.splice(index, 1); 1778 tmpArray2.push({label:(ZmMsg.sendOnBehalfOf + " " + email), value:(ZmMsg.sendOnBehalfOf + " " + email)}); 1779 } 1780 1781 // Add sendAs emails 1782 for (var i=0;i < appCtxt.sendAsEmails.length; i++){ 1783 email = appCtxt.sendAsEmails[i].addr; 1784 index = -1; 1785 if ((index = AjxUtil.indexOf(fromAddress,email)) != -1) 1786 fromAddress.splice(index, 1); 1787 if ((index = AjxUtil.indexOf(displayOptions,email)) != -1) 1788 displayOptions.splice(index, 1); 1789 tmpArray2.push({label:email, value:email}); 1790 } 1791 1792 1793 if (fromAddress && fromAddress.length) 1794 fromAddress = fromAddress.sort(); 1795 1796 if (displayOptions && displayOptions.length) 1797 displayOptions = displayOptions.sort(); 1798 1799 displayOptions = AjxUtil.mergeArrays(displayOptions, fromAddress); 1800 1801 var length = displayOptions.length; 1802 for (var i=0;i<length; i++){ 1803 tmpArray1.push({label:displayOptions[i], value:displayOptions[i]}); 1804 } 1805 this._selectFromLabels = tmpArray1.concat(tmpArray2); 1806 } 1807 return this._selectFromLabels; 1808 }; 1809 1810 1811 ZmAccountsPage.prototype._setupSelect = 1812 function(id, setup, value) { 1813 var select; 1814 if (id == "FROM_EMAIL") { 1815 setup.displayOptions = this._getAllAddresses(); 1816 var fromAddress = appCtxt.get(ZmSetting.MAIL_FROM_ADDRESS); 1817 setup.options = this._setSelectFromLabels(setup.displayOptions, fromAddress ); 1818 setup.choices = setup.options; 1819 if (appCtxt.get(ZmSetting.ALLOW_ANY_FROM_ADDRESS)) { 1820 select = this._setupComboBox(id, setup, value); 1821 // By setting the setSelectedValue method on the combox 1822 // box, it fakes the setter method of a DwtSelect. 1823 select.setSelectedValue = select.setValue; 1824 // NOTE: For this control, we always want the text value 1825 select.getValue = select.getText; 1826 } 1827 } 1828 else if (setup.displayOptions && setup.displayOptions.length < 2) { 1829 select = this._setupInput(id, setup, value); 1830 select.setEnabled(false); 1831 select.setSelectedValue = select.setValue; 1832 } 1833 if (!select) { 1834 select = ZmPreferencesPage.prototype._setupSelect.apply(this, arguments); 1835 } 1836 if (id == "PROVIDER") { 1837 select.addChangeListener(new AjxListener(this, this._handleProviderChange)); 1838 } 1839 return select; 1840 }; 1841 1842 ZmAccountsPage.__BY_PROVIDER_NAME = function(a, b) { 1843 if (a.name.match(/^zimbra/i)) return -1; 1844 if (b.name.match(/^zimbra/i)) return 1; 1845 if (a.name.match(/^yahoo/i)) return -1; 1846 if (b.name.match(/^yahoo/i)) return 1; 1847 return a.name.localeCompare(b.name); 1848 }; 1849 1850 ZmAccountsPage.prototype._setupComboBox = 1851 function(id, setup, value) { 1852 if (id == "REPLY_TO_EMAIL") { 1853 var addresses = this._getAllAddresses(); 1854 var accounts = [].concat(appCtxt.getDataSourceCollection().getImapAccounts(), appCtxt.getDataSourceCollection().getPopAccounts()); 1855 addresses = this._getAddressesFromAccounts(accounts, addresses, true, true); 1856 setup.displayOptions = addresses; 1857 } 1858 return ZmPreferencesPage.prototype._setupComboBox.apply(this, arguments); 1859 }; 1860 1861 ZmAccountsPage.prototype._updateComboBox = 1862 function(id, extras) { 1863 var dwtElement = this.getFormObject(id); 1864 if (dwtElement && AjxUtil.isFunction(dwtElement.removeAll) && AjxUtil.isFunction(dwtElement.add)) { 1865 if (id == "REPLY_TO_EMAIL") { 1866 if (!AjxUtil.isArray(extras)) 1867 extras = AjxUtil.isString(extras) ? [extras] : []; 1868 1869 var addresses = this._getAllAddresses().concat(extras); 1870 var accounts = this._accounts.getArray(); 1871 addresses = this._getAddressesFromAccounts(accounts, addresses, true, true); 1872 1873 dwtElement.removeAll(); 1874 for (var i=0; i<addresses.length; i++) { 1875 dwtElement.add(addresses[i], addresses[i], false); 1876 } 1877 } 1878 } 1879 }; 1880 1881 1882 1883 1884 1885 ZmAccountsPage.prototype._setupCustom = 1886 function(id, setup, value) { 1887 if (id == ZmSetting.ACCOUNTS) { 1888 // setup list 1889 var listView = this._accountListView = new ZmAccountsListView(this); 1890 listView.addSelectionListener(new AjxListener(this, this._handleAccountSelection)); 1891 this.setFormObject(id, listView); 1892 1893 // setup buttons 1894 this._setupButtons(); 1895 1896 // setup account sections 1897 this._setupPrimaryDiv(); 1898 this._setupExternalDiv(); 1899 this._setupPersonaDiv(); 1900 1901 // initialize list 1902 this._resetAccountListView(); 1903 1904 return listView; 1905 } 1906 if (id == "TEST") { 1907 var button = new DwtButton({parent:this}); 1908 button.setText(setup.displayName); 1909 button.addSelectionListener(new AjxListener(this, this._handleTestButton)); 1910 return button; 1911 } 1912 if (id == "WHEN_IN_FOLDER_BUTTON") { 1913 var button = new DwtButton({parent:this}); 1914 button.setImage("SearchFolder"); 1915 button.addSelectionListener(new AjxListener(this, this._handleFolderButton)); 1916 return button; 1917 } 1918 if (id == "ALERT") { 1919 return new DwtAlert(this); 1920 } 1921 1922 return ZmPreferencesPage.prototype._setupCustom.apply(this, arguments); 1923 }; 1924 1925 ZmAccountsPage.prototype._getAllAddresses = 1926 function() { 1927 var username = appCtxt.get(ZmSetting.USERNAME); 1928 var addresses = appCtxt.get(ZmSetting.ALLOW_FROM_ADDRESSES); 1929 var aliases = appCtxt.get(ZmSetting.MAIL_ALIASES); 1930 return [].concat(username, addresses, aliases); 1931 }; 1932 1933 /* 1934 * Takes a list of accounts and extracts their email addresses 1935 * @param accounts array of account objects 1936 * @param unique boolean: if true, addresses will be included in output only if they are not already present. Defaults to true 1937 * @param valid boolean: if true, performs a validation check on the address and only includes it if it passes. Defaults to true 1938 * @param addresses optional array of addresses (as strings) to append to. Defaults to an empty array 1939 */ 1940 ZmAccountsPage.prototype._getAddressesFromAccounts = function(accounts, addresses, unique, valid) { 1941 if (!AjxUtil.isArray(addresses)) 1942 addresses = []; 1943 for (var i=0; i<accounts.length; i++) { 1944 var account = accounts[i]; 1945 if (account.isMain || account.enabled) { 1946 var address = account.getEmail(); 1947 if (!AjxUtil.isEmpty(address) && (!valid || AjxEmailAddress.isValid(address)) && (!unique || AjxUtil.indexOf(addresses, address, false) == -1)) // Make sure we are not adding an empty address and that we are not adding the address twice 1948 addresses.push(address); 1949 } 1950 } 1951 return addresses; 1952 }; 1953 1954 ZmAccountsPage.prototype._resetAccountListView = 1955 function(accountOrIndex) { 1956 var accounts = this._accounts.clone(); 1957 var count = accounts.size(); 1958 // NOTE: We go backwards so we don't have to adjust index when we remove an item. 1959 for (var i = count - 1; i >= 0; i--) { 1960 var account = accounts.get(i); 1961 if (account.type == ZmAccount.TYPE_ZIMBRA && !account.isMain && !account.visible) { 1962 accounts.removeAt(i); 1963 } 1964 } 1965 this._accountListView.set(accounts); 1966 var account = accountOrIndex; 1967 if (AjxUtil.isNumber(account)) { 1968 var index = accountOrIndex; 1969 var list = this._accountListView.getList(); 1970 var size = list.size(); 1971 if (accountOrIndex >= size) { 1972 index = size - 1; 1973 } 1974 account = list.get(index); 1975 } 1976 this._accountListView.setSelection(account || appCtxt.accountList.mainAccount); 1977 this._updateReplyToEmail(); 1978 }; 1979 1980 // account buttons 1981 1982 ZmAccountsPage.prototype._setupButtons = 1983 function() { 1984 var deleteButtonDiv = document.getElementById(this._htmlElId+"_DELETE"); 1985 if (deleteButtonDiv) { 1986 var button = new DwtButton({parent:this}); 1987 button.setText(ZmMsg.del); 1988 button.setEnabled(false); 1989 button.addSelectionListener(new AjxListener(this, this._handleDeleteButton)); 1990 this._replaceControlElement(deleteButtonDiv, button); 1991 this._deleteButton = button; 1992 } 1993 1994 var addExternalButtonDiv = document.getElementById(this._htmlElId+"_ADD_EXTERNAL"); 1995 if (addExternalButtonDiv) { 1996 var button = new DwtButton({parent:this}); 1997 button.setText(ZmMsg.addExternalAccount); 1998 button.addSelectionListener(new AjxListener(this, this._handleAddExternalButton)); 1999 this._replaceControlElement(addExternalButtonDiv, button); 2000 this._addExternalButton = button; 2001 } 2002 2003 var addPersonaButtonDiv = document.getElementById(this._htmlElId+"_ADD_PERSONA"); 2004 if (addPersonaButtonDiv) { 2005 var button = new DwtButton({parent:this}); 2006 button.setText(ZmMsg.addPersona); 2007 button.addSelectionListener(new AjxListener(this, this._handleAddPersonaButton)); 2008 this._replaceControlElement(addPersonaButtonDiv, button); 2009 this._addPersonaButton = button; 2010 } 2011 }; 2012 2013 // account sections 2014 2015 2016 ZmAccountsPage.prototype._getSectionDiv = 2017 function(account) { 2018 return appCtxt.isOffline 2019 ? ((account.type == ZmAccount.TYPE_PERSONA) ? this._sectionDivs[account.type] : this._sectionDivs[ZmAccount.TYPE_ZIMBRA] ) 2020 : this._sectionDivs[account.type]; 2021 }; 2022 2023 ZmAccountsPage.prototype._setupPrimaryDiv = 2024 function() { 2025 var div = document.getElementById(this._htmlElId+"_PRIMARY"); 2026 if (div) { 2027 this._sectionDivs[ZmAccount.TYPE_ZIMBRA] = div; 2028 this._createSection("PRIMARY", div); 2029 } 2030 }; 2031 2032 ZmAccountsPage.prototype._setupExternalDiv = 2033 function() { 2034 // setup generic external account div 2035 var div = document.getElementById(this._htmlElId+"_EXTERNAL"); 2036 if (div) { 2037 this._sectionDivs[ZmAccount.TYPE_POP] = div; 2038 this._sectionDivs[ZmAccount.TYPE_IMAP] = div; 2039 this._createSection("EXTERNAL", div); 2040 } 2041 2042 // setup divs for specific providers 2043 var providers = ZmDataSource.getProviders(); 2044 for (var id in providers) { 2045 var div = document.getElementById([this._htmlElId, id].join("_")); 2046 if (!div) continue; 2047 this._sectionDivs[id] = div; 2048 this._createSection(id, div); 2049 } 2050 }; 2051 2052 ZmAccountsPage.prototype._setupPersonaDiv = 2053 function() { 2054 var div = document.getElementById(this._htmlElId+"_PERSONA"); 2055 if (div) { 2056 this._sectionDivs[ZmAccount.TYPE_PERSONA] = div; 2057 this._createSection("PERSONA", div); 2058 } 2059 }; 2060 2061 ZmAccountsPage.prototype._createSection = 2062 function(name, sectionDiv) { 2063 var section = ZmAccountsPage.SECTIONS[name]; 2064 var prefIds = section && section.prefs; 2065 if (!prefIds) return; 2066 2067 this._enterTabScope(); 2068 try { 2069 this._addTabLinks(sectionDiv); 2070 2071 section.controls = {}; 2072 2073 var prefs = ZmAccountsPage.PREFS; 2074 for (var i = 0; i < prefIds.length; i++) { 2075 var id = prefIds[i]; 2076 var setup = prefs[id]; 2077 if (!setup) continue; 2078 2079 var containerId = [this._htmlElId, name, id].join("_"); 2080 var containerEl = document.getElementById(containerId); 2081 if (!containerEl) continue; 2082 2083 this._initControl(id, setup, value, name); 2084 2085 var type = setup.displayContainer; 2086 var value = null; 2087 var control; 2088 switch (type) { 2089 case ZmPref.TYPE_STATIC: { 2090 control = this._setupStatic(id, setup, value); 2091 break; 2092 } 2093 case ZmPref.TYPE_INPUT: { 2094 control = this._setupInput(id, setup, value); 2095 break; 2096 } 2097 case ZmPref.TYPE_SELECT: { 2098 control = this._setupSelect(id, setup, value); 2099 break; 2100 } 2101 case ZmPref.TYPE_COMBOBOX: { 2102 control = this._setupComboBox(id, setup, value); 2103 break; 2104 } 2105 case ZmPref.TYPE_CHECKBOX: { 2106 control = this._setupCheckbox(id, setup, value); 2107 break; 2108 } 2109 case ZmPref.TYPE_RADIO_GROUP: { 2110 control = this._setupRadioGroup(id, setup, value); 2111 break; 2112 } 2113 case ZmPref.TYPE_CUSTOM: { 2114 control = this._setupCustom(id, setup, value); 2115 break; 2116 } 2117 default: continue; 2118 } 2119 2120 if (control) { 2121 if (name == "PRIMARY" && id == "EMAIL") { 2122 control.setEnabled(false); 2123 } 2124 this._replaceControlElement(containerEl, control); 2125 if (type == ZmPref.TYPE_RADIO_GROUP) { 2126 control = this.getFormObject(id); 2127 } 2128 section.controls[id] = control; 2129 } 2130 } 2131 2132 section.tabGroup = new DwtTabGroup(name); 2133 this._addControlsToTabGroup(section.tabGroup); 2134 } 2135 finally { 2136 this._exitTabScope(); 2137 } 2138 }; 2139 2140 // listeners 2141 2142 ZmAccountsPage.prototype._handleAccountSelection = 2143 function(evt) { 2144 var account = this._accountListView.getSelection()[0]; 2145 this.setAccount(account); 2146 }; 2147 2148 ZmAccountsPage.prototype._handleDeleteButton = 2149 function(evt) { 2150 var account = this._accountListView.getSelection()[0]; 2151 if (!account._new) { 2152 account._deleted = true; 2153 this._deletedAccounts.push(account); 2154 } 2155 var index = this._accountListView.getItemIndex(account); 2156 if (account.type == ZmAccount.TYPE_PERSONA) { 2157 var personaList = ZmNewPersona.getPersonaList(this._accountListView.getList().getArray()); 2158 var personaListLength = personaList.length; 2159 2160 // If there's only one persona or the last added persona are being deleted then reset the personal display count. 2161 if (personaListLength === 1) { 2162 ZmNewPersona.ID = 0; 2163 } 2164 else if (personaListLength === index) { 2165 if (ZmNewPersona.ID > 0) { 2166 ZmNewPersona.ID--; 2167 } 2168 } 2169 } 2170 2171 this._accounts.remove(account); 2172 this._resetAccountListView(index); 2173 }; 2174 2175 ZmAccountsPage.prototype._handleAddExternalButton = 2176 function(evt) { 2177 var account = new ZmNewDataSource(); 2178 this._accounts.add(account); 2179 this._accounts.sort(ZmAccountsPage.__ACCOUNT_COMPARATOR); 2180 this._resetAccountListView(account); 2181 }; 2182 2183 ZmAccountsPage.prototype._handleAddPersonaButton = 2184 function(evt) { 2185 var persona = new ZmNewPersona(); 2186 this._accounts.add(persona); 2187 this._accounts.sort(ZmAccountsPage.__ACCOUNT_COMPARATOR); 2188 this._resetAccountListView(persona); 2189 }; 2190 2191 ZmAccountsPage.prototype._updateList = 2192 function(account) { 2193 var lv = this._accountListView; 2194 var email = AjxStringUtil.htmlEncode(account.getEmail()); 2195 var identity = account.getIdentity(); 2196 if (!account.isMain && identity && identity.sendFromAddressType == ZmSetting.SEND_ON_BEHALF_OF){ 2197 email = appCtxt.getUsername() + " " + ZmMsg.sendOnBehalfOf + " " + email; 2198 } 2199 2200 lv.setCellContents(account, ZmItem.F_NAME, AjxStringUtil.htmlEncode(account.getName())); 2201 lv.setCellContents(account, ZmItem.F_EMAIL,email); 2202 lv.setCellContents(account, ZmItem.F_TYPE, AjxStringUtil.htmlEncode(lv._getAccountType(account))); 2203 }; 2204 2205 // generic listeners 2206 2207 ZmAccountsPage.prototype._handleNameChange = 2208 function(evt) { 2209 var inputEl = DwtUiEvent.getTarget(evt); 2210 var newName = inputEl.value; 2211 this._accountListView.setCellContents(this._currentAccount, ZmItem.F_NAME, AjxStringUtil.htmlEncode(newName)); 2212 this._setControlValue("HEADER", this._currentSection, newName); 2213 2214 if (this._currentAccount.identity) { 2215 this._currentAccount.identity.name = newName; 2216 } 2217 2218 var type = this._currentAccount.type; 2219 if (type == ZmAccount.TYPE_POP || type == ZmAccount.TYPE_IMAP) { 2220 this._setDownloadToFolder(this._currentAccount); 2221 } 2222 }; 2223 2224 ZmAccountsPage.prototype._handleEmailChange = 2225 function(evt) { 2226 // update email cell 2227 var section = this._currentSection; 2228 var email = this._getControlValue("EMAIL", section); 2229 this._updateEmailCell(email); 2230 2231 // auto-fill username and host 2232 var m = email.match(/^(.*?)(?:@(.*))?$/); 2233 if (!m) return; 2234 2235 var dataSource = this._currentAccount; 2236 if (dataSource.userName == "") { 2237 this._setControlValue("USERNAME", section, m[1]); 2238 } 2239 if (m[2] && dataSource.mailServer == "") { 2240 this._setControlValue("HOST", section, m[2]); 2241 } 2242 this._updateReplyToEmail(email); 2243 }; 2244 2245 ZmAccountsPage.prototype._updateEmailCell = 2246 function(email) { 2247 this._accountListView.setCellContents(this._currentAccount, ZmItem.F_EMAIL, AjxStringUtil.htmlEncode(email)); 2248 }; 2249 2250 ZmAccountsPage.prototype._updateReplyToEmail = 2251 function(email) { 2252 if (AjxEmailAddress.isValid(email)) { 2253 this._updateComboBox("REPLY_TO_EMAIL", email); 2254 } else { 2255 this._updateComboBox("REPLY_TO_EMAIL"); 2256 } 2257 }; 2258 2259 // data source listeners 2260 2261 ZmAccountsPage.prototype._handleTypeChange = 2262 function(evt) { 2263 var type = ZmAccount.getTypeName(this._getControlValue("ACCOUNT_TYPE", this._currentSection)); 2264 this._accountListView.setCellContents(this._currentAccount, ZmItem.F_TYPE, AjxStringUtil.htmlEncode(type)); 2265 this._handleTypeOrSslChange(evt); 2266 }; 2267 2268 ZmAccountsPage.prototype._handleDownloadTo = 2269 function(evt) { 2270 var isInbox = this._getControlValue("DOWNLOAD_TO", this._currentSection) == ZmAccountsPage.DOWNLOAD_TO_INBOX; 2271 this._currentAccount.folderId = isInbox ? ZmOrganizer.ID_INBOX : -1; 2272 }; 2273 2274 ZmAccountsPage.prototype._handleProviderChange = 2275 function() { 2276 var id = this._getControlValue("PROVIDER", this._currentSection); 2277 var dataSource = this._currentAccount; 2278 2279 // initialize data source 2280 if (id) { 2281 var provider = ZmDataSource.getProviders()[id]; 2282 if (!provider) return; 2283 2284 // init default values 2285 dataSource.reset(); 2286 for (var p in provider) { 2287 if (p == "id") continue; 2288 if (p == "type") { 2289 dataSource.setType(provider[p]); 2290 continue; 2291 } 2292 if (ZmDataSource.DATASOURCE_ATTRS[p]) { 2293 dataSource[ZmDataSource.DATASOURCE_ATTRS[p]] = provider[p]; 2294 } 2295 } 2296 } 2297 2298 // reset interface 2299 var skipUpdate = true; 2300 var ignoreProvider = id == ""; 2301 this.setAccount(dataSource, skipUpdate, ignoreProvider); 2302 }; 2303 2304 ZmAccountsPage.prototype._handleTypeOrSslChange = 2305 function(evt) { 2306 var dataSource = this._currentAccount; 2307 var section = this._currentSection; 2308 if (dataSource._new) { 2309 var type = this._getControlValue("ACCOUNT_TYPE", section); 2310 if (!type) { 2311 type = appCtxt.get(ZmSetting.POP_ACCOUNTS_ENABLED) ? ZmAccount.TYPE_POP : ZmAccount.TYPE_IMAP; 2312 } 2313 dataSource.setType(type); 2314 2315 var isPop = type == ZmAccount.TYPE_POP; 2316 this._setControlEnabled("DELETE_AFTER_DOWNLOAD", this._currentSection, isPop); 2317 this._setControlEnabled("DOWNLOAD_TO", this._currentSection, isPop); 2318 } 2319 2320 var ssl = this._getControlValue("SSL", section) == ZmDataSource.CONNECT_SSL; 2321 dataSource.connectionType = ssl ? ZmDataSource.CONNECT_SSL : ZmDataSource.CONNECT_CLEAR; 2322 dataSource.port = dataSource.getDefaultPort(); 2323 this._setPortControls(dataSource.type, dataSource.connectionType, dataSource.port); 2324 }; 2325 2326 ZmAccountsPage.prototype._handleUserNameChange = 2327 function(evt) { 2328 var userName = this._getControlValue("USERNAME", this._currentSection); 2329 this._currentAccount.userName = userName; 2330 if (!this._getControlValue("EMAIL", this._currentSection)) { 2331 var provider = ZmDataSource.getProviderForAccount(this._currentAccount); 2332 var email = userName && provider && provider._host ? [userName,provider._host].join("@") : userName; 2333 this._updateEmailCell(email); 2334 } 2335 }; 2336 2337 ZmAccountsPage.prototype._handleHostChange = 2338 function(evt) { 2339 this._currentAccount.mailServer = this._getControlValue("HOST", this._currentSection); 2340 }; 2341 2342 ZmAccountsPage.prototype._handleChangePort = 2343 function(evt) { 2344 this._setControlEnabled("PORT", this._currentSection, evt.detail); 2345 }; 2346 2347 ZmAccountsPage.prototype._handleTestButton = 2348 function(evt) { 2349 var button = evt.item; 2350 button.setEnabled(false); 2351 2352 // make sure that the current object proxy is up-to-date 2353 var dataSource = this._currentAccount; 2354 this._setAccountFields(dataSource, this._currentSection); 2355 2356 // check values 2357 if (!dataSource.userName || !dataSource.mailServer || !dataSource.port) { 2358 appCtxt.setStatusMsg(ZmMsg.accountTestErrorMissingInfo, ZmStatusView.LEVEL_CRITICAL); 2359 button.setEnabled(true); 2360 return; 2361 } 2362 2363 // testconnection 2364 var accounts = [ dataSource ]; 2365 var callback = new AjxCallback(this, this._testFinish, [button]); 2366 this._testAccounts(accounts, callback, callback); 2367 }; 2368 2369 ZmAccountsPage.prototype._testFinish = 2370 function(button) { 2371 button.setEnabled(true); 2372 }; 2373 2374 // identity listeners 2375 2376 ZmAccountsPage.prototype._handleReplyTo = 2377 function(evt) { 2378 this._setReplyToControls(); 2379 }; 2380 2381 ZmAccountsPage.prototype._handleWhenSentTo = 2382 function(evt) { 2383 this._setWhenSentToControls(); 2384 }; 2385 2386 ZmAccountsPage.prototype._handleWhenInFolder = 2387 function(evt) { 2388 this._setWhenInFolderControls(); 2389 }; 2390 2391 ZmAccountsPage.prototype._handleFolderButton = 2392 function(evt) { 2393 if (!this._folderAddCallback) { 2394 this._folderAddCallback = new AjxCallback(this, this._handleFolderAdd); 2395 } 2396 var dialog = appCtxt.getChooseFolderDialog(); 2397 var params = {overviewId: dialog.getOverviewId(ZmApp.MAIL), appName:ZmApp.MAIL}; 2398 ZmController.showDialog(dialog, this._folderAddCallback, params); 2399 }; 2400 2401 ZmAccountsPage.prototype._handleFolderAdd = 2402 function(folder) { 2403 var section = this._currentSection; 2404 var folders = this._getControlValue("WHEN_IN_FOLDER_LIST", section); 2405 if (!folders) return; 2406 2407 folders.push(folder.id); 2408 this._setControlValue("WHEN_IN_FOLDER_LIST", section, folders); 2409 appCtxt.getChooseFolderDialog().popdown(); 2410 }; 2411 2412 // pre-save callbacks 2413 2414 ZmAccountsPage.prototype._preSave = 2415 function(continueCallback) { 2416 // make sure that the current object proxy is up-to-date 2417 this._setAccountFields(this._currentAccount, this._currentSection); 2418 2419 if (appCtxt.isOffline) { 2420 // skip account tests 2421 this._preSaveCreateFolders(continueCallback); 2422 } else { 2423 // perform account tests 2424 this._preSaveTest(continueCallback); 2425 } 2426 2427 }; 2428 2429 ZmAccountsPage.prototype._preSaveTest = 2430 function(continueCallback) { 2431 // get dirty external accounts 2432 var dirtyAccounts = []; 2433 var accounts = this._accounts.getArray(); 2434 for (var i = 0; i < accounts.length; i++) { 2435 var account = accounts[i]; 2436 if (account.type == ZmAccount.TYPE_POP || account.type == ZmAccount.TYPE_IMAP) { 2437 if (account._new || account._dirty) { 2438 dirtyAccounts.push(account); 2439 } 2440 } 2441 } 2442 2443 // test for invalid name 2444 for (var i = 0; i < dirtyAccounts.length; i++) { 2445 var account = dirtyAccounts[i]; 2446 if (account.type == ZmAccount.TYPE_IMAP && account.name.match(/^\s*inbox\s*$/i)) { 2447 var params = { 2448 msg: AjxMessageFormat.format(ZmMsg.accountNameReserved, [AjxStringUtil.htmlEncode(account.name)]), 2449 level: ZmStatusView.LEVEL_CRITICAL 2450 }; 2451 appCtxt.setStatusMsg(params); 2452 continueCallback.run(false); 2453 return; 2454 } 2455 } 2456 2457 // test external accounts 2458 if (dirtyAccounts.length > 0) { 2459 var okCallback = new AjxCallback(this, this._preSaveTestOk, [continueCallback, dirtyAccounts]); 2460 var cancelCallback = new AjxCallback(this, this._preSaveTestCancel, [continueCallback]); 2461 this._testAccounts(dirtyAccounts, okCallback, cancelCallback); 2462 } 2463 2464 // perform next step 2465 else { 2466 this._preSaveCreateFolders(continueCallback); 2467 } 2468 }; 2469 2470 ZmAccountsPage.prototype._preSaveTestOk = 2471 function(continueCallback, accounts, successes) { 2472 // en/disable accounts based on test results 2473 for (var i = 0; i < accounts.length; i++) { 2474 accounts[i].enabled = successes[i]; 2475 } 2476 2477 // continue 2478 this._preSaveCreateFolders(continueCallback); 2479 }; 2480 2481 ZmAccountsPage.prototype._preSaveTestCancel = 2482 function(continueCallback) { 2483 if (continueCallback) { 2484 continueCallback.run(false); 2485 } 2486 }; 2487 2488 ZmAccountsPage.prototype._preSaveCreateFolders = 2489 function(continueCallback) { 2490 var batchCmd; 2491 var root = appCtxt.getById(ZmOrganizer.ID_ROOT); 2492 var accounts = this._accounts.getArray(); 2493 for (var i = 0; i < accounts.length; i++) { 2494 var account = accounts[i]; 2495 if (account.type == ZmAccount.TYPE_POP || account.type == ZmAccount.TYPE_IMAP) { 2496 if (account.folderId != ZmOrganizer.ID_INBOX) { 2497 var name = AjxStringUtil.trim(account.getName()); 2498 if (!batchCmd) { batchCmd = new ZmBatchCommand(false); } 2499 2500 // avoid folder create if it already exists 2501 var folder = root.getByName(name, true); 2502 if (folder) { 2503 var folderId = folder.id; 2504 if (folder.type !== ZmId.ORG_FOLDER) { 2505 if (folder.parent.id == ZmOrganizer.ID_ROOT) { 2506 //e.g. calendar that's child of root - wouldn't be able to create the folder for the account with that same name. (despite it being mail). So bail. 2507 var params = { 2508 msg: AjxMessageFormat.format(ZmMsg.errorAlreadyExists, [AjxStringUtil.htmlEncode(name), ZmMsg[folder.type.toLowerCase()]]), 2509 level: ZmStatusView.LEVEL_CRITICAL 2510 }; 2511 appCtxt.setStatusMsg(params); 2512 continueCallback.run(false); 2513 return; 2514 } 2515 //otherwise this continues on with creating the folder since this folder is not interfering (it's not a root child folder) 2516 } 2517 else if (folderId != ZmOrganizer.ID_INBOX && Number(folderId) < 256) { 2518 var params = { 2519 msg: AjxMessageFormat.format(ZmMsg.accountNameReserved, [AjxStringUtil.htmlEncode(name)]), 2520 level: ZmStatusView.LEVEL_CRITICAL 2521 }; 2522 appCtxt.setStatusMsg(params); 2523 continueCallback.run(false); 2524 return; 2525 } 2526 // if there already is a folder by this name in Trash, rename the trashed folder 2527 else if (folder.isInTrash()) { 2528 folder.rename(folder.name+"_"); 2529 } 2530 else { 2531 account.folderId = folder.id; 2532 continue; 2533 } 2534 } 2535 2536 // this means user modified name of the folder, so let's rename it 2537 folder = account._object_ && appCtxt.getById(account._object_.folderId); 2538 if (folder && Number(folder.id) >= 256) { 2539 if (folder.name != name) { 2540 var soapDoc = AjxSoapDoc.create("FolderActionRequest", "urn:zimbraMail"); 2541 var actionNode = soapDoc.set("action"); 2542 actionNode.setAttribute("op", "rename"); 2543 actionNode.setAttribute("id", folder.id); 2544 actionNode.setAttribute("name", name); 2545 2546 var callback = new AjxCallback(this, this._handleRenameFolderResponse, [account, folder]); 2547 batchCmd.addNewRequestParams(soapDoc, callback, callback); 2548 } 2549 else { 2550 account.folderId = folder.id; 2551 } 2552 } else { 2553 var soapDoc = AjxSoapDoc.create("CreateFolderRequest", "urn:zimbraMail"); 2554 var folderEl = soapDoc.set("folder"); 2555 folderEl.setAttribute("l", ZmOrganizer.ID_ROOT); 2556 folderEl.setAttribute("name", name); 2557 folderEl.setAttribute("fie", "1"); // fetch-if-exists 2558 2559 var callback = new AjxCallback(this, this._handleCreateFolderResponse, [account]); 2560 batchCmd.addNewRequestParams(soapDoc, callback, callback); 2561 } 2562 } 2563 } 2564 } 2565 2566 // continue 2567 if (batchCmd && batchCmd.size() > 0) { 2568 // HACK: Don't know a better way to set an error condition 2569 this.__hack_preSaveSuccess = true; 2570 var callback = new AjxCallback(this, this._preSaveFinish, [continueCallback]); 2571 batchCmd.run(callback); 2572 } 2573 else { 2574 this._preSaveFinish(continueCallback); 2575 } 2576 }; 2577 2578 ZmAccountsPage.prototype._handleCreateFolderResponse = 2579 function(dataSource, result) { 2580 var resp = result && result._data && result._data.CreateFolderResponse; 2581 if (resp) { 2582 dataSource.folderId = ZmOrganizer.normalizeId(resp.folder[0].id); 2583 } 2584 else { 2585 // HACK: Don't know a better way to set an error condition 2586 this.__hack_preSaveSuccess = false; 2587 } 2588 }; 2589 2590 ZmAccountsPage.prototype._handleRenameFolderResponse = 2591 function(dataSource, folder, result) { 2592 var resp = result && result._data && result._data.FolderActionResponse; 2593 if (resp) { 2594 dataSource.folderId = ZmOrganizer.normalizeId(folder.id); 2595 } 2596 else { 2597 // HACK: Don't know a better way to set an error condition 2598 this.__hack_preSaveSuccess = false; 2599 } 2600 }; 2601 2602 ZmAccountsPage.prototype._preSaveFinish = 2603 function(continueCallback, result, exceptions) { 2604 // HACK: Don't know a better way to set an error condition 2605 continueCallback.run(this.__hack_preSaveSuccess && (!exceptions || exceptions.length == 0)); 2606 }; 2607 2608 // save callbacks 2609 2610 ZmAccountsPage.prototype._handleSaveAccount = 2611 function(account, resp) { 2612 2613 delete account._dirty; 2614 2615 var mboxes = appCtxt.accountList.getAccounts(); 2616 var active = appCtxt.getActiveAccount(); 2617 2618 // Save data from old proxies to proxied objects 2619 for (var j in mboxes) { 2620 var acct = mboxes[j]; 2621 if (active.isMain || acct == active) { 2622 var acct = ZmAccountsPage.__unProxy(mboxes[j]._proxy_); 2623 if (acct) { 2624 mboxes[j] = acct; 2625 } 2626 } 2627 } 2628 }; 2629 2630 ZmAccountsPage.prototype._handleSaveVisibleAccount = 2631 function() { 2632 var accounts = this._accounts.getArray(); 2633 for (var i = 0; i < accounts.length; i++) { 2634 var account = accounts[i]; 2635 account._object_.visible = account.visible; 2636 delete account._visibleDirty; 2637 } 2638 var setting = appCtxt.getSettings().getSetting(ZmSetting.CHILD_ACCTS_VISIBLE); 2639 setting._notify(ZmEvent.E_MODIFY); 2640 }; 2641 2642 ZmAccountsPage.prototype._handleCreateAccount = 2643 function(account, resp) { 2644 delete account._new; 2645 account._needsSync = true; 2646 }; 2647 2648 ZmAccountsPage.prototype._promptToDeleteFolder = function(organizer) { 2649 var dialog = appCtxt.getConfirmationDialog(); 2650 var prompt = AjxMessageFormat.format(ZmMsg.accountDeleteFolder, [organizer.getName()]); 2651 var callback = new AjxCallback(this, this._handleDeleteFolder, [organizer]); 2652 dialog.popup(prompt, callback); 2653 }; 2654 2655 ZmAccountsPage.prototype._handleDeleteFolder = function(organizer) { 2656 var trash = appCtxt.getById(ZmOrganizer.ID_TRASH); 2657 organizer.move(trash); 2658 }; 2659 2660 2661 ZmAccountsPage.prototype._postSave = 2662 function() { 2663 var needsSync = []; 2664 var accounts = this._accounts.getArray(); 2665 for (var i = 0; i < accounts.length; i++) { 2666 var account = accounts[i]; 2667 if (account._needsSync) { 2668 needsSync.push(account); 2669 } 2670 if (account instanceof ZmDataSource) { 2671 delete account.password; 2672 } 2673 } 2674 2675 if (needsSync.length) { 2676 var dsCollection = AjxDispatcher.run("GetDataSourceCollection"); 2677 for (var i = 0; i < needsSync.length; i++) { 2678 var account = needsSync[i]; 2679 dsCollection.importMailFor(account.folderId); 2680 delete account._needsSync; 2681 } 2682 } 2683 }; 2684 2685 ZmAccountsPage.prototype._handleAddApplicationCode = 2686 function() { 2687 if (!this._addApplicationCodeDlg) { 2688 var appPasscodeCallback = this._getAppSpecificPasswords.bind(this); 2689 this._addApplicationCodeDlg = new ZmApplicationCodeDialog(appPasscodeCallback); 2690 } 2691 this._addApplicationCodeDlg.popup(); 2692 }; 2693 2694 ZmAccountsPage.prototype._revokeApplicationCode = 2695 function() { 2696 var item = this.appPasscodeList.getSelection()[0]; 2697 if (item) { 2698 var jsonObj = {RevokeAppSpecificPasswordRequest : {_jsns : "urn:zimbraAccount", appName : item.appName}}; 2699 var respCallback = this._handleRevokeApplicationCode.bind(this); 2700 appCtxt.getAppController().sendRequest({jsonObj:jsonObj, asyncMode:true, callback:respCallback}); 2701 } 2702 }; 2703 2704 ZmAccountsPage.prototype._handleRevokeApplicationCode = 2705 function() { 2706 this._getAppSpecificPasswords(); 2707 }; 2708 2709 ZmAccountsPage.prototype._getAppSpecificPasswords = 2710 function() { 2711 var jsonObj = {GetAppSpecificPasswordsRequest : {_jsns : "urn:zimbraAccount"}}; 2712 var respCallback = this._getAppSpecificPasswordsCallback.bind(this); 2713 appCtxt.getAppController().sendRequest({jsonObj:jsonObj, asyncMode:true, callback:respCallback}); 2714 }; 2715 2716 ZmAccountsPage.prototype._getAppSpecificPasswordsCallback = 2717 function(appSpecificPasswords) { 2718 var applicationCodesElement = document.getElementById(this._htmlElId + "_APPLICATION_CODES") || (this.appPasscodeList && this.appPasscodeList.getHtmlElement()); 2719 var appSpecificPasswordsList = this._setAppSpecificPasswords(appSpecificPasswords); 2720 if (!appSpecificPasswordsList) { 2721 appSpecificPasswordsList = new AjxVector(); 2722 } 2723 var appPasscodeList = new ZmAccountAppPasscodeListView(this); 2724 this.appPasscodeList = appPasscodeList; 2725 appPasscodeList.replaceElement(applicationCodesElement); 2726 appPasscodeList.set(appSpecificPasswordsList); 2727 appPasscodeList.addSelectionListener(this._appPasscodeSelectionListener.bind(this)); 2728 this.revokeApplicationCodeButton.setEnabled(false); 2729 }; 2730 2731 ZmAccountsPage.prototype._setAppSpecificPasswords = 2732 function(appSpecificPasswords) { 2733 var response = appSpecificPasswords.getResponse(); 2734 if (!response || !response.GetAppSpecificPasswordsResponse) { 2735 return; 2736 } 2737 var appSpecificPasswordsResponse = response.GetAppSpecificPasswordsResponse; 2738 var passwordData = appSpecificPasswordsResponse && appSpecificPasswordsResponse.appSpecificPasswords && appSpecificPasswordsResponse.appSpecificPasswords.passwordData; 2739 if (!passwordData) { 2740 return; 2741 } 2742 var vector = AjxVector.fromArray(passwordData); 2743 vector.sort(this._compareAppPasscodes); 2744 return vector; 2745 }; 2746 2747 ZmAccountsPage.prototype._compareAppPasscodes = 2748 function(a, b) { 2749 return a.appName < b.appName ? -1 : (a.appName > b.appName ? 1 : 0); 2750 }; 2751 2752 ZmAccountsPage.prototype._appPasscodeSelectionListener = 2753 function() { 2754 this.revokeApplicationCodeButton.setEnabled(!!this.appPasscodeList.getSelectionCount()); 2755 }; 2756 2757 // 2758 // Private functions 2759 // 2760 2761 ZmAccountsPage.__ACCOUNT_COMPARATOR = 2762 function(a, b) { 2763 if (a.type == ZmAccount.TYPE_ZIMBRA && (a.isMain || appCtxt.isOffline)) return -1; 2764 if (b.type == ZmAccount.TYPE_ZIMBRA && (b.isMain || appCtxt.isOffline)) return 1; 2765 return a.getName().localeCompare(b.getName()); 2766 }; 2767 2768 ZmAccountsPage.__createProxy = 2769 function(account) { 2770 delete account._object_; 2771 var identity = account.getIdentity(); 2772 var identityProxy = AjxUtil.createProxy(identity); 2773 var proxy = AjxUtil.createProxy(account); 2774 proxy._identity = identityProxy; 2775 account._proxy_ = proxy; 2776 proxy.getIdentity = AjxCallback.simpleClosure(function(){return this._identity}, proxy, identityProxy); 2777 return proxy; 2778 }; 2779 2780 ZmAccountsPage.__proxy_getIdentity = 2781 function(identity) { 2782 return identity; 2783 }; 2784 2785 ZmAccountsPage.__unProxy = 2786 function(accountProxy) { 2787 var account = AjxUtil.unProxy(accountProxy); 2788 if (!account) return accountProxy; 2789 var identityProxy = accountProxy._identity; 2790 var identity = AjxUtil.unProxy(identityProxy); 2791 account.getIdentity = AjxCallback.simpleClosure(ZmAccountsPage.__proxy_getIdentity, account, identity); 2792 return account; 2793 } 2794 2795 // 2796 // Classes 2797 // 2798 2799 ZmAccountsListView = function(parent, className, posStyle, noMaximize) { 2800 className = className || "DwtListView"; 2801 className += " ZOptionsItemsListView"; 2802 DwtListView.call(this, {parent:parent, className:className, posStyle:posStyle, 2803 headerList:this._getHeaderList(), noMaximize:noMaximize}); 2804 this.setMultiSelect(false); 2805 this._view = ZmId.VIEW_ACCOUNT; 2806 }; 2807 ZmAccountsListView.prototype = new DwtListView; 2808 ZmAccountsListView.prototype.constructor = ZmAccountsListView; 2809 2810 ZmAccountsListView.prototype.toString = 2811 function() { 2812 return "ZmAccountsListView"; 2813 }; 2814 2815 // Constants 2816 2817 ZmAccountsListView.WIDTH_NAME = ZmMsg.COLUMN_WIDTH_NAME_ACC; 2818 ZmAccountsListView.WIDTH_STATUS = ZmMsg.COLUMN_WIDTH_STATUS_ACC; 2819 ZmAccountsListView.WIDTH_TYPE = ZmMsg.COLUMN_WIDTH_TYPE_ACC; 2820 2821 // Public methods 2822 2823 ZmAccountsListView.prototype.getCellElement = 2824 function(account, field) { 2825 return document.getElementById(this._getCellId(account, field)); 2826 }; 2827 2828 ZmAccountsListView.prototype.setCellContents = 2829 function(account, field, html) { 2830 var el = this.getCellElement(account, field); 2831 if (!el) { return; } 2832 2833 if (field == ZmItem.F_NAME) { 2834 el = document.getElementById(this._getCellId(account, field)+"_name"); 2835 } 2836 if(field == ZmItem.F_EMAIL) { 2837 html = "<div style='margin-left: 10px;'>"+ html +"</div>"; 2838 } 2839 el.innerHTML = html; 2840 }; 2841 2842 // Protected methods 2843 2844 ZmAccountsListView.prototype._getCellContents = 2845 function(buffer, i, item, field, col, params) { 2846 if (field == ZmItem.F_NAME) { 2847 var cellId = this._getCellId(item, field); 2848 buffer[i++] = "<div id='"; 2849 buffer[i++] = cellId; 2850 buffer[i++] = "_name'>"; 2851 buffer[i++] = AjxStringUtil.htmlEncode(item.getName()); 2852 buffer[i++] = "</div>"; 2853 return i; 2854 } 2855 if (field == ZmItem.F_STATUS) { 2856 if (item instanceof ZmDataSource && !item.isStatusOk()) { 2857 buffer[i++] = "<table border=0 cellpadding=0 cellpadding=0><tr>"; 2858 buffer[i++] = "<td><div class='ImgCritical_12'></div></td><td>"; 2859 buffer[i++] = ZmMsg.ALT_ERROR; 2860 buffer[i++] = "</td></tr></table>"; 2861 } 2862 else { 2863 buffer[i++] = AjxMsg.ok; 2864 } 2865 return i; 2866 } 2867 if (field == ZmItem.F_EMAIL) { 2868 var email = item.getEmail(); 2869 var identity = item.getIdentity(); 2870 if (!item.isMain && identity.sendFromAddressType == ZmSetting.SEND_ON_BEHALF_OF) email = appCtxt.getActiveAccount().name + " " + ZmMsg.sendOnBehalfOf + " " + email; 2871 buffer[i++] = "<div style='margin-left: 10px;'>"+ AjxStringUtil.htmlEncode(email) +"</div>"; 2872 return i; 2873 } 2874 if (field == ZmItem.F_TYPE) { 2875 buffer[i++] = this._getAccountType(item); 2876 return i; 2877 } 2878 return DwtListView.prototype._getCellContents.apply(this, arguments); 2879 }; 2880 2881 ZmAccountsListView.prototype._getCellId = 2882 function(item, field, params) { 2883 return DwtId.getListViewItemId(DwtId.WIDGET_ITEM_CELL, this._view, item.id, field); 2884 }; 2885 2886 ZmAccountsListView.prototype._getHeaderList = 2887 function() { 2888 return [ 2889 new DwtListHeaderItem({field:ZmItem.F_NAME, text:ZmMsg.accountName, width:ZmAccountsListView.WIDTH_NAME}), 2890 new DwtListHeaderItem({field:ZmItem.F_STATUS, text:ZmMsg.status, width:ZmAccountsListView.WIDTH_STATUS, align:"center"}), 2891 new DwtListHeaderItem({field:ZmItem.F_EMAIL, text:ZmMsg.emailAddr}), 2892 new DwtListHeaderItem({field:ZmItem.F_TYPE, text:ZmMsg.type, width:ZmAccountsListView.WIDTH_TYPE}) 2893 ]; 2894 }; 2895 2896 ZmAccountsListView.prototype._getAccountType = 2897 function(account) { 2898 var provider = ZmDataSource.getProviderForAccount(account); 2899 return (provider && AjxStringUtil.htmlEncode(provider.name)) || (account.isMain ? ZmMsg.accountTypePrimary : ZmAccount.getTypeName(account.type)); 2900 }; 2901 2902 // Delegate Permissions 2903 2904 ZmAccountDelegatesListView = function(parent, className, posStyle, noMaximize) { 2905 className = className || "DwtListView"; 2906 className += " ZOptionsItemsListView"; 2907 DwtListView.call(this, {parent:parent, className:className, posStyle:posStyle, 2908 headerList:this._getHeaderList(), noMaximize:noMaximize}); 2909 this.setMultiSelect(false); 2910 }; 2911 ZmAccountDelegatesListView.prototype = new DwtListView; 2912 ZmAccountDelegatesListView.prototype.constructor = ZmAccountDelegatesListView; 2913 2914 ZmAccountDelegatesListView.prototype.toString = 2915 function() { 2916 return "ZmAccountDelegatesListView"; 2917 }; 2918 2919 // Constants 2920 2921 ZmAccountDelegatesListView.WIDTH_NAME = ZmMsg.COLUMN_WIDTH_NAME_ACC; 2922 ZmAccountDelegatesListView.WIDTH_STATUS = ZmMsg.COLUMN_WIDTH_STATUS_ACC; 2923 ZmAccountDelegatesListView.WIDTH_TYPE = ZmMsg.COLUMN_WIDTH_TYPE_ACC; 2924 2925 // Public methods 2926 2927 ZmAccountDelegatesListView.prototype.getCellElement = 2928 function(account, field) { 2929 return document.getElementById(this._getCellId(account, field)); 2930 }; 2931 2932 ZmAccountDelegatesListView.prototype.setCellContents = 2933 function(account, field, html) { 2934 var el = this.getCellElement(account, field); 2935 if (!el) { return; } 2936 2937 if (field == ZmItem.F_NAME) { 2938 el = document.getElementById(this._getCellId(account, field)+"_name"); 2939 } 2940 if(field == ZmItem.F_EMAIL) { 2941 html = "<div style='margin-left: 10px;'>"+ html +"</div>"; 2942 } 2943 el.innerHTML = html; 2944 }; 2945 2946 // Protected methods 2947 2948 ZmAccountDelegatesListView.prototype._getCellContents = 2949 function(buffer, i, item, field, col, params) { 2950 if (field == ZmItem.F_NAME) { 2951 var cellId = this._getCellId(item, field); 2952 buffer[i++] = "<div id='"; 2953 buffer[i++] = cellId; 2954 buffer[i++] = "_name' style='margin:0 5px; overflow:hidden;'>"; 2955 buffer[i++] = AjxStringUtil.htmlEncode(item.user); 2956 buffer[i++] = "</div>"; 2957 return i; 2958 } 2959 if (field == ZmItem.F_TYPE) { 2960 var cellId = this._getCellId(item, field); 2961 buffer[i++] = "<div id='"; 2962 buffer[i++] = cellId; 2963 buffer[i++] = "_type' style='margin:0 5px;'>"; 2964 buffer[i++] = (item.sendAs && item.sendOnBehalfOf) ? ZmMsg.sendAsAndSendOnBehalfOf : (item.sendAs ? ZmMsg.sendAs : ZmMsg.sendOnBehalfOflbl); 2965 buffer[i++] = "</div>"; 2966 return i; 2967 } 2968 return DwtListView.prototype._getCellContents.apply(this, arguments); 2969 }; 2970 2971 ZmAccountDelegatesListView.prototype._getCellId = 2972 function(item, field, params) { 2973 return DwtId.getListViewItemId(DwtId.WIDGET_ITEM_CELL, this._view, item.id, field); 2974 }; 2975 2976 ZmAccountDelegatesListView.prototype._getHeaderList = 2977 function() { 2978 return [ 2979 new DwtListHeaderItem({field:ZmItem.F_NAME, text:ZmMsg.name, width:ZmMsg.COLUMN_WIDTH_NAME_DELEGATE, margin:"5px"}), 2980 new DwtListHeaderItem({field:ZmItem.F_TYPE, text:ZmMsg.type}) 2981 ]; 2982 }; 2983 2984 ZmAccountDelegatesListView.prototype._doubleClickAction = 2985 function(){ 2986 this.parent._editDelegateButton(); 2987 } 2988 2989 ZmAccountAppPasscodeListView = function(parent, className, posStyle, noMaximize) { 2990 className = className || "DwtListView"; 2991 className += " ZOptionsItemsListView"; 2992 DwtListView.call(this, {parent:parent, className:className, posStyle:posStyle, headerList:this._getHeaderList(), noMaximize:noMaximize}); 2993 this.setMultiSelect(false); 2994 }; 2995 ZmAccountAppPasscodeListView.prototype = new DwtListView; 2996 ZmAccountAppPasscodeListView.prototype.constructor = ZmAccountAppPasscodeListView; 2997 2998 ZmAccountAppPasscodeListView.prototype.toString = 2999 function() { 3000 return "ZmAccountAppPasscodeListView"; 3001 }; 3002 3003 ZmAccountAppPasscodeListView.prototype._getHeaderList = 3004 function() { 3005 return [ 3006 new DwtListHeaderItem({field:ZmItem.F_NAME, text:ZmMsg.name, margin:"5px", width:ZmMsg.COLUMN_WIDTH_NAME_APPLICATION}), 3007 new DwtListHeaderItem({field:ZmItem.F_APP_PASSCODE_CREATED, text:ZmMsg.created, width:ZmMsg.COLUMN_WIDTH_NAME_APPLICATION}), 3008 new DwtListHeaderItem({field:ZmItem.F_APP_PASSCODE_LAST_USED, text:ZmMsg.lastUsed, width:ZmMsg.COLUMN_WIDTH_NAME_APPLICATION}) 3009 ]; 3010 }; 3011 3012 ZmAccountAppPasscodeListView.prototype._getCellContents = 3013 function(buffer, i, item, field, col, params) { 3014 if (field == ZmItem.F_NAME) { 3015 var cellId = this._getCellId(item, field); 3016 buffer[i++] = "<div id='"; 3017 buffer[i++] = cellId; 3018 buffer[i++] = "_name' style='margin:0 5px; overflow:hidden;'>"; 3019 buffer[i++] = AjxStringUtil.htmlEncode(item.appName); 3020 buffer[i++] = "</div>"; 3021 return i; 3022 } 3023 else if (field == ZmItem.F_APP_PASSCODE_CREATED) { 3024 var cellId = this._getCellId(item, field); 3025 buffer[i++] = "<div id='"; 3026 buffer[i++] = cellId; 3027 buffer[i++] = "_type' style='margin:0 5px;'>"; 3028 buffer[i++] = AjxDateFormat.format(AjxDateFormat.SHORT, new Date(item.created)); 3029 buffer[i++] = "</div>"; 3030 return i; 3031 } 3032 else if (field == ZmItem.F_APP_PASSCODE_LAST_USED) { 3033 var cellId = this._getCellId(item, field); 3034 buffer[i++] = "<div id='"; 3035 buffer[i++] = cellId; 3036 buffer[i++] = "_type' style='margin:0 5px;'>"; 3037 if (item.lastUsed) { 3038 buffer[i++] = AjxDateFormat.format(AjxDateFormat.SHORT, new Date(item.lastUsed)); 3039 } 3040 else { 3041 buffer[i++] = "-"; 3042 } 3043 buffer[i++] = "</div>"; 3044 return i; 3045 } 3046 return DwtListView.prototype._getCellContents.apply(this, arguments); 3047 }; 3048 3049 3050 // 3051 // New data source class 3052 // 3053 3054 ZmAccountsPage._defineClasses = 3055 function() { 3056 ZmNewDataSource = function() { 3057 var number = ++ZmNewDataSource.ID; 3058 this.setType(appCtxt.get(ZmSetting.POP_ACCOUNTS_ENABLED) ? ZmAccount.TYPE_POP : ZmAccount.TYPE_IMAP); 3059 ZmDataSource.call(this, this.type, ("new-dsrc-"+number)); 3060 this.email = ""; 3061 this.name = AjxMessageFormat.format(ZmMsg.newExternalAccount, number); 3062 this._new = true; 3063 this.folderId = -1; 3064 var identity = this.getIdentity(); 3065 identity.sendFromDisplay = appCtxt.get(ZmSetting.DISPLAY_NAME); 3066 identity.sendFromAddress = appCtxt.get(ZmSetting.USERNAME); 3067 }; 3068 ZmNewDataSource.prototype = new ZmDataSource; 3069 ZmNewDataSource.prototype.constructor = ZmNewDataSource; 3070 3071 ZmNewDataSource.prototype.toString = 3072 function() { 3073 return "ZmNewDataSource"; 3074 }; 3075 3076 // Constants 3077 3078 ZmNewDataSource.ID = 0; 3079 3080 // Data 3081 3082 ZmNewDataSource.prototype.ELEMENT_NAME = ZmPopAccount.prototype.ELEMENT_NAME; 3083 3084 // Public methods 3085 3086 ZmNewDataSource.prototype.setType = 3087 function(type) { 3088 this.type = type; 3089 var TYPE = this.type == ZmAccount.TYPE_POP ? ZmPopAccount : ZmImapAccount; 3090 this.ELEMENT_NAME = TYPE.prototype.ELEMENT_NAME; 3091 this.getDefaultPort = TYPE.prototype.getDefaultPort; 3092 }; 3093 3094 // 3095 // New persona class 3096 // 3097 3098 ZmNewPersona = function() { 3099 var number = ++ZmNewPersona.ID; 3100 var id = "new-persona-"+number; 3101 var name = AjxMessageFormat.format(ZmMsg.newPersona, number); 3102 var identity = new ZmIdentity(name); 3103 identity.id = id; 3104 ZmPersona.call(this, identity); 3105 this.id = id; 3106 this._new = true; 3107 identity.sendFromDisplay = appCtxt.get(ZmSetting.DISPLAY_NAME); 3108 identity.sendFromAddress = appCtxt.get(ZmSetting.USERNAME); 3109 }; 3110 ZmNewPersona.prototype = new ZmPersona; 3111 ZmNewPersona.prototype.constructor = ZmNewPersona; 3112 3113 ZmNewPersona.prototype.toString = 3114 function() { 3115 return "ZmNewPersona"; 3116 }; 3117 3118 // Constants 3119 3120 ZmNewPersona.ID = 0; 3121 3122 /** 3123 * Fetches the list of personas added to account list view amongst other accounts. 3124 * 3125 * 3126 * @param {String} accountList List of accounts added to account list view e.g. Persona and External (POP) account. 3127 * 3128 * 3129 * @public 3130 */ 3131 ZmNewPersona.getPersonaList = 3132 function(accountList) { 3133 var personas = []; 3134 3135 personas = AjxUtil.filter(accountList, function(accountItem) { 3136 if (accountItem instanceof ZmNewPersona || accountItem.type == ZmAccount.TYPE_PERSONA) { 3137 return accountItem; 3138 } 3139 }); 3140 3141 return personas; 3142 }; 3143 3144 }; // function ZmAccountsPage._defineClasses 3145 3146 3147 // GrantRights Dialog 3148 3149 3150 /** 3151 * Creates a grantRights Dialog. 3152 * @class 3153 * This class represents a rename folder dialog. 3154 * 3155 * @param {DwtComposite} parent the parent 3156 * @param {String} className the class name 3157 * 3158 * @extends ZmDialog 3159 */ 3160 ZmGrantRightsDialog = function(parent, className, callback) { 3161 3162 ZmDialog.call(this, {parent:parent, className:className, title:ZmMsg.grantRights, id:"GrantRightsDialog"}); 3163 var id = this.toString(); 3164 var inputId = id + "_name"; 3165 var cellId = id + "_name_cell"; 3166 var rowId = id + "_name_row"; 3167 var sendAsId = id + "_sendAs"; 3168 var sendOboId = id + "_sendObo"; 3169 3170 var aifParams = { 3171 parent: parent, 3172 bubbleAddedCallback: this._onChange.bind(this), 3173 bubbleRemovedCallback: this._onChange.bind(this), 3174 singleBubble: true, 3175 inputId: inputId, 3176 type: AjxEmailAddress.TO 3177 } 3178 3179 this._editPermissions = false; 3180 this._okCallBack = callback; 3181 3182 this._addrInputField = new ZmAddressInputField(aifParams); 3183 this._aifId = this._addrInputField._htmlElId; 3184 3185 this._delegateEmailInput = document.getElementById(inputId); 3186 this._delegateEmailRow = document.getElementById(rowId); 3187 this._sendAs = document.getElementById(sendAsId); 3188 this._sendObo = document.getElementById(sendOboId); 3189 3190 this._addrInputField.reparentHtmlElement(cellId); 3191 this._initAutoComplete(); 3192 }; 3193 3194 ZmGrantRightsDialog.prototype = new ZmDialog; 3195 ZmGrantRightsDialog.prototype.constructor = ZmGrantRightsDialog; 3196 3197 ZmGrantRightsDialog.prototype.toString = 3198 function() { 3199 return "ZmGrantRightsDialog"; 3200 }; 3201 3202 /** 3203 * Pops-up the dialog. 3204 * 3205 */ 3206 ZmGrantRightsDialog.prototype.popup = 3207 function() { 3208 this._addrInputField.clear(); 3209 ZmDialog.prototype.popup.call(this); 3210 if (!this._editPermissions){ 3211 this._delegateEmailInput.focus(); 3212 } else { 3213 this._sendAs.focus(); 3214 } 3215 }; 3216 3217 ZmGrantRightsDialog.prototype._contentHtml = 3218 function() { 3219 var subs = {id: this.toString()}; 3220 return AjxTemplate.expand("prefs.Pages#GrantRightsDialog",subs); 3221 }; 3222 3223 ZmGrantRightsDialog.prototype._okButtonListener = 3224 function(ev) { 3225 // get email address from the bubble 3226 var emailsFromBubbles = this._addrInputField.getAddresses(true); 3227 var delegateEmail = emailsFromBubbles[0] && emailsFromBubbles[0].address; 3228 if (!delegateEmail) { 3229 // get email address from the plain text in input if no bubbles 3230 var emailsFromText = AjxEmailAddress.getValidAddresses(this._delegateEmailInput.value).getArray(); 3231 delegateEmail = (emailsFromText[0] && emailsFromText[0].address) || this._delegateEmailInput.value; 3232 } 3233 this._okCallBack.run(delegateEmail, this._sendAs.checked, this._sendObo.checked); 3234 }; 3235 3236 ZmGrantRightsDialog.prototype.setData = 3237 function(item){ 3238 if (item){ 3239 this.setTitle(ZmMsg.editDelegatePermissions + " - " + item.user); 3240 this._delegateEmailRow.style.display ="none"; 3241 this._sendAs.checked = item.sendAs; 3242 this._sendObo.checked = item.sendOnBehalfOf; 3243 this._editPermissions = true; 3244 this._prevData = item; 3245 } else { 3246 this.setTitle(ZmMsg.delegatePermissions); 3247 this._delegateEmailRow.style.display =""; 3248 this._delegateEmailInput.value=""; 3249 this._sendAs.checked = false; 3250 this._sendObo.checked = false; 3251 this._editPermissions = false; 3252 Dwt.setHandler(this._delegateEmailInput, DwtEvent.ONCHANGE, this._onChange.bind(this)); 3253 } 3254 this.getButton(DwtDialog.OK_BUTTON).setEnabled(false); 3255 Dwt.setHandler(this._sendAs, DwtEvent.ONCLICK, this._onChange.bind(this)); 3256 Dwt.setHandler(this._sendObo, DwtEvent.ONCLICK, this._onChange.bind(this)); 3257 }; 3258 ZmGrantRightsDialog.prototype._initAutoComplete = 3259 function(){ 3260 if (appCtxt.get(ZmSetting.CONTACTS_ENABLED) || appCtxt.get(ZmSetting.GAL_ENABLED)) { 3261 var params = { 3262 parent: appCtxt.getShell(), 3263 dataClass: appCtxt.getAutocompleter(), 3264 options: {type:ZmAutocomplete.AC_TYPE_GAL, acType:ZmAutocomplete.AC_TYPE_CONTACT, excludeGroups:true}, 3265 matchValue: ZmAutocomplete.AC_VALUE_FULL, 3266 separator: "", 3267 galType: ZmSearch.GAL_ACCOUNT, 3268 contextId: this.toString() 3269 }; 3270 this._acAddrSelectList = new ZmAutocompleteListView(params); 3271 this._acAddrSelectList.handle(this._delegateEmailInput, this._aifId); 3272 this._addrInputField.setAutocompleteListView(this._acAddrSelectList); 3273 } 3274 }; 3275 3276 ZmGrantRightsDialog.prototype._onChange = 3277 function(){ 3278 var enable = false; 3279 if (!this._editPermissions){ 3280 enable = (this._delegateEmailInput.value || this._addrInputField.getValue()) 3281 && (this._sendAs.checked || this._sendObo.checked); 3282 } else { 3283 enable = this._prevData.sendAs !== this._sendAs.checked 3284 || this._prevData.sendOnBehalfOf !== this._sendObo.checked; 3285 } 3286 this.getButton(DwtDialog.OK_BUTTON).setEnabled(enable); 3287 3288 } 3289