package net.xmind.signin.internal; import java.io.UnsupportedEncodingException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.util.ArrayList; import java.util.List; import java.util.Properties; import net.xmind.signin.IButtonCreator; import net.xmind.signin.IDataStore; import net.xmind.signin.ISignInDialogExtension; import net.xmind.signin.ISignInDialogExtension2; import net.xmind.signin.XMindNet; import org.apache.commons.codec.binary.Base64; import org.apache.commons.httpclient.HttpStatus; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.IJobChangeEvent; import org.eclipse.core.runtime.jobs.IJobChangeListener; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.resource.JFaceResources; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.StackLayout; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Text; import org.xmind.ui.resources.FontUtils; public class SignInDialog2 extends Dialog implements IJobChangeListener, IButtonCreator { private static class InternalSignInJob extends Job { private String user; private String password; // private boolean remember; private XMindNetRequest request = null; private IDataStore data; public InternalSignInJob(String user, String passwrod) { super("Sign in to XMind.net"); //$NON-NLS-1$ setSystem(true); this.user = user; this.password = passwrod; // this.remember = remember; } public IDataStore getData() { return data; } @Override protected void canceling() { if (request != null) { request.abort(); } super.canceling(); } private String hash(String password) { MessageDigest md5; try { try { // Try BouncyCastle: md5 = MessageDigest.getInstance("MD5", "BC"); //$NON-NLS-1$ //$NON-NLS-2$ } catch (NoSuchProviderException e) { md5 = MessageDigest.getInstance("MD5"); //$NON-NLS-1$ } } catch (NoSuchAlgorithmException e) { return null; } Base64 encoder = new Base64(); try { return new String(encoder.encode(md5.digest(password .getBytes("UTF-8"))), "UTF-8"); //$NON-NLS-1$ //$NON-NLS-2$ } catch (UnsupportedEncodingException e) { return null; } } @Override protected IStatus run(IProgressMonitor monitor) { if (monitor.isCanceled()) return Status.CANCEL_STATUS; request = new XMindNetRequest(true); request.uri("/_res/token/%s", user); //$NON-NLS-1$ request.addParameter("user", user); //$NON-NLS-1$ String pwdhash = hash(password); if (pwdhash != null) { request.addParameter("pwd", pwdhash); //$NON-NLS-1$ } else { request.addParameter("password", password); //$NON-NLS-1$ } // request.addParameter("remember", "true"); //$NON-NLS-1$ //$NON-NLS-2$ request.post(); if (monitor.isCanceled() || request.isAborted()) return Status.CANCEL_STATUS; int code = request.getCode(); IDataStore data = request.getData(); if (code == HttpStatus.SC_OK) { if (data != null) { this.data = data; return Status.OK_STATUS; } return error(code, Messages.SignInDialog_ApplicationError_message, request.getException()); } else if (code == XMindNetRequest.ERROR) { return error(code, Messages.SignInDialog_NetworkError_message, request.getException()); } else if (code >= 400 && code < 500) { return error(code, Messages.SignInDialog_RequestError_message, null); } else { return error(code, Messages.SignInDialog_ServerError_message, null); } } private static IStatus error(int code, String message, Throwable exception) { return new Status(IStatus.WARNING, Activator.PLUGIN_ID, code, message, exception); } } private boolean sheet; private String message; private String errorMessage = null; private ISignInDialogExtension extension; private Text nameField; private Text passwordField; //private Button rememberCheck; private Composite messageArea; private Composite errorMessageArea; private Label errorLabel; private Properties data; private Job signInJob; private List<Integer> buttonIds = new ArrayList<Integer>(); public SignInDialog2(Shell parentShell) { this(parentShell, null, null, false, null); } public SignInDialog2(Shell parentShell, String message, ISignInDialogExtension extension) { this(parentShell, message, extension, false, null); } public SignInDialog2(Shell parentShell, String message, ISignInDialogExtension extension, boolean sheet, Properties data) { super(parentShell); this.message = message == null ? Messages.SignInDialog_message : message; this.extension = extension; this.sheet = sheet; this.data = data == null ? new Properties() : data; if (sheet) { setShellStyle(getShellStyle() | SWT.SHEET); } setBlockOnOpen(true); } @Override protected Control createDialogArea(Composite parent) { if (message != null) { createMessageArea(parent); createSeparator(parent); } Composite composite = (Composite) super.createDialogArea(parent); createFormArea(composite); return composite; } private void createMessageArea(Composite parent) { Composite messageStack = new Composite(parent, SWT.NONE); StackLayout layout = new StackLayout(); layout.marginHeight = 0; layout.marginWidth = 0; messageStack.setLayout(layout); GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, false); gridData.widthHint = 480; gridData.heightHint = SWT.DEFAULT; messageStack.setLayoutData(gridData); messageArea = createMessagePage(messageStack); createMessageIcon(messageArea, SWT.ICON_INFORMATION); createMessageLabel(messageArea, message); errorMessageArea = createMessagePage(messageStack); createMessageIcon(errorMessageArea, SWT.ICON_WARNING); errorLabel = createMessageLabel(errorMessageArea, errorMessage); setErrorMessage(errorMessage); } private Composite createMessagePage(Composite parent) { Composite composite = new Composite(parent, SWT.NONE); GridLayout gridLayout = new GridLayout(2, false); gridLayout.marginWidth = 15; gridLayout.marginHeight = 10; gridLayout.verticalSpacing = 5; gridLayout.horizontalSpacing = 10; composite.setLayout(gridLayout); composite.setBackground(parent.getDisplay().getSystemColor( SWT.COLOR_LIST_BACKGROUND)); return composite; } private Label createMessageIcon(Composite parent, int image) { Label icon = new Label(parent, SWT.NONE); GridData gridData = new GridData(SWT.BEGINNING, SWT.CENTER, false, true); gridData.widthHint = SWT.DEFAULT; gridData.heightHint = SWT.DEFAULT; icon.setLayoutData(gridData); icon.setBackground(parent.getBackground()); icon.setImage(parent.getDisplay().getSystemImage(image)); return icon; } private Label createMessageLabel(Composite parent, String message) { Label label = new Label(parent, SWT.WRAP); GridData gridData = new GridData(SWT.FILL, SWT.CENTER, true, true); gridData.widthHint = SWT.DEFAULT; gridData.heightHint = SWT.DEFAULT; label.setLayoutData(gridData); label.setBackground(parent.getBackground()); label.setForeground(parent.getDisplay().getSystemColor( SWT.COLOR_LIST_FOREGROUND)); label.setFont(FontUtils.getRelativeHeight(JFaceResources.DEFAULT_FONT, -1)); if (message != null) label.setText(message); return label; } private void createSeparator(Composite parent) { Label sep = new Label(parent, SWT.SEPARATOR | SWT.HORIZONTAL); GridData gridData = new GridData(SWT.FILL, SWT.CENTER, true, false); gridData.widthHint = SWT.DEFAULT; gridData.heightHint = SWT.DEFAULT; sep.setLayoutData(gridData); } private void createFormArea(Composite parent) { Composite form = new Composite(parent, SWT.NONE); form.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); GridLayout gridLayout = new GridLayout(2, false); gridLayout.marginWidth = 30; gridLayout.marginHeight = 25; gridLayout.marginBottom = 15; gridLayout.verticalSpacing = 12; gridLayout.horizontalSpacing = 7; form.setLayout(gridLayout); // Row 1: createNameLabel(form); createNameField(form); // createSignUpButton(form); // Row 2: createPasswordLabel(form); createPasswordField(form); // createForgotPasswordButton(form); // Row 3: Label emptyPlaceholder = new Label(form, SWT.NONE); emptyPlaceholder.setLayoutData(new GridData(SWT.END, SWT.CENTER, false, false)); Control forgotButton = createForgotPasswordButton(form); ((GridData) forgotButton.getLayoutData()).verticalIndent = -10; } private void createNameLabel(Composite parent) { Label label = new Label(parent, SWT.NONE); label.setLayoutData(new GridData(SWT.END, SWT.CENTER, false, false)); label.setText(Messages.SignInDialog_NameField_text); label.setFont(FontUtils.getBold(JFaceResources.DEFAULT_FONT)); } private void createNameField(Composite parent) { nameField = new Text(parent, SWT.BORDER | SWT.SINGLE); nameField .setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); ((GridData) nameField.getLayoutData()).widthHint = 160; nameField.setText(data.getProperty(XMindNetAccount.USER, "")); //$NON-NLS-1$ nameField.addListener(SWT.Modify, new Listener() { public void handleEvent(Event event) { data.setProperty(XMindNetAccount.USER, nameField.getText()); setErrorMessage(null); } }); nameField.addListener(SWT.FocusIn, new Listener() { public void handleEvent(Event event) { nameField.selectAll(); } }); } private Control createSignUpButton(Composite parent) { Control link = createLink(parent, Messages.SignInDialog_NotMember_text, new Runnable() { public void run() { XMindNet.gotoURL(true, "https://www.xmind.net/xmind/signup/"); //$NON-NLS-1$ // close(); } }); link.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false)); return link; } private void createPasswordLabel(Composite parent) { Label label = new Label(parent, SWT.NONE); label.setLayoutData(new GridData(SWT.END, SWT.CENTER, false, false)); label.setText(Messages.SignInDialog_PasswordField_text); label.setFont(FontUtils.getBold(JFaceResources.DEFAULT_FONT)); } private void createPasswordField(Composite parent) { passwordField = new Text(parent, SWT.BORDER | SWT.SINGLE | SWT.PASSWORD); passwordField.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); ((GridData) passwordField.getLayoutData()).widthHint = 160; passwordField.addListener(SWT.Modify, new Listener() { public void handleEvent(Event event) { setErrorMessage(null); } }); passwordField.addListener(SWT.FocusIn, new Listener() { public void handleEvent(Event event) { passwordField.selectAll(); } }); } private Control createForgotPasswordButton(Composite parent) { Control link = createLink(parent, Messages.SignInDialog_ForgotPassword_text, new Runnable() { public void run() { XMindNet.gotoURL(true, "https://www.xmind.net/xmind/forgotpassword/"); //$NON-NLS-1$ // close(); } }); link.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false)); return link; } private Control createLink(final Composite parent, String text, final Runnable openHandler) { final Label link = new Label(parent, SWT.NONE); link.setText(text); link.setCursor(parent.getDisplay().getSystemCursor(SWT.CURSOR_HAND)); final Color normalColor = parent.getDisplay().getSystemColor( SWT.COLOR_BLUE); link.setForeground(normalColor); link.setFont(FontUtils.getRelativeHeight(JFaceResources.DEFAULT_FONT, -1)); Listener listener = new Listener() { boolean pressed = false; boolean inside = false; Color pressedColor = parent.getDisplay().getSystemColor( SWT.COLOR_DARK_MAGENTA); public void handleEvent(Event event) { if (event.type == SWT.MouseDown) { pressed = true; inside = true; link.setForeground(pressedColor); } else if (event.type == SWT.MouseUp) { boolean shouldRun = pressed && inside; pressed = false; inside = false; link.setForeground(normalColor); if (shouldRun) { openHandler.run(); } } else if (event.type == SWT.MouseExit) { if (pressed) { inside = false; } } else if (event.type == SWT.MouseEnter) { if (pressed) { inside = true; } } } }; link.addListener(SWT.MouseDown, listener); link.addListener(SWT.MouseUp, listener); link.addListener(SWT.MouseExit, listener); link.addListener(SWT.MouseEnter, listener); return link; } protected Control createButtonBar(Composite parent) { Composite composite = new Composite(parent, SWT.NONE); composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); GridLayout gridLayout = new GridLayout(hasButtonBarContributor() ? 1 : 2, false); gridLayout.marginWidth = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_MARGIN); gridLayout.marginHeight = 0; gridLayout.marginBottom = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_MARGIN); gridLayout.verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING); gridLayout.horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING); composite.setLayout(gridLayout); createExpandedArea(composite); Composite buttonBar = new Composite(composite, SWT.NONE); // create a layout with spacing and margins appropriate for the font // size. GridLayout layout = new GridLayout(); layout.numColumns = 0; // this is incremented by createButton layout.makeColumnsEqualWidth = false; layout.marginWidth = 0; layout.marginHeight = 0; layout.horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING); layout.verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING); buttonBar.setLayout(layout); buttonBar.setLayoutData(new GridData(SWT.END, SWT.CENTER, true, true)); buttonBar.setFont(parent.getFont()); // Add the buttons to the button bar. createButtonsForButtonBar(buttonBar); return buttonBar; } private void createExpandedArea(Composite parent) { Composite composite = new Composite(parent, SWT.NONE); composite .setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); GridLayout gridLayout = new GridLayout(1, false); gridLayout.marginWidth = 0; gridLayout.marginHeight = 0; gridLayout.verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING); gridLayout.horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING); composite.setLayout(gridLayout); createSignUpButton(composite); //createRememberCheck(composite); if (extension != null) { createExtensionControls(composite); } } private boolean hasButtonBarContributor() { return extension instanceof ISignInDialogExtension2; } // private void createRememberCheck(Composite parent) { // rememberCheck = new Button(parent, SWT.CHECK); // rememberCheck.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, // false)); // rememberCheck.setText(Messages.SignInDialog_Remember_text); // } private void createExtensionControls(Composite parent) { Composite composite = new Composite(parent, SWT.NONE); composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); extension.contributeToOptions(this, composite); if (composite.getChildren().length == 0) { composite.dispose(); } } @Override public void create() { super.create(); nameField.setFocus(); } /* * (non-Javadoc) * * @see * net.xmind.signin.IButtonCreator#doCreateButton(org.eclipse.swt.widgets * .Composite, int, java.lang.String) */ public Button doCreateButton(Composite parent, int id, String label) { buttonIds.add(Integer.valueOf(id)); return createButton(parent, id, label, false); } @Override protected void createButtonsForButtonBar(Composite parent) { createButton(parent, IDialogConstants.OK_ID, Messages.SignInDialog_SignIn_text, true); if (sheet) { createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CANCEL_LABEL, false); } if (extension instanceof ISignInDialogExtension2) { ((ISignInDialogExtension2) extension).contributeToButtonBar(this, parent, this); } } protected void configureShell(final Shell newShell) { super.configureShell(newShell); newShell.setText(Messages.SignInDialog_title); } /* * (non-Javadoc) * * @see org.eclipse.jface.dialogs.Dialog#buttonPressed(int) */ @Override protected void buttonPressed(int buttonId) { if (buttonId != IDialogConstants.OK_ID && buttonId != IDialogConstants.CANCEL_ID) { if (extension instanceof ISignInDialogExtension2) { ((ISignInDialogExtension2) extension).handleButtonPressed(this, buttonId); return; } } super.buttonPressed(buttonId); } private void changeButton(int buttonId, boolean enabled, String withLabel) { Button button = getButton(buttonId); if (button != null && !button.isDisposed()) { if (withLabel != null) button.setText(withLabel); button.setEnabled(enabled); } } @Override protected void okPressed() { changeButton(IDialogConstants.OK_ID, false, Messages.SignInDialog_SigningIn_text); for (Integer buttonId : buttonIds) { changeButton(buttonId.intValue(), false, null); } startJob(); } @Override public boolean close() { setReturnCode(CANCEL); return doClose(); } private boolean doClose() { boolean closed = super.close(); if (closed) { stopJob(); } return closed; } private void startJob() { stopJob(); signInJob = new InternalSignInJob(nameField.getText(), passwordField.getText()); signInJob.addJobChangeListener(this); signInJob.schedule(); } private void stopJob() { if (signInJob != null) { signInJob.removeJobChangeListener(this); signInJob.cancel(); signInJob = null; } } public String getUserID() { return data == null ? null : data.getProperty(XMindNetAccount.USER); } public String getToken() { return data == null ? null : data.getProperty(XMindNetAccount.TOKEN); } // public boolean shouldRemember() { // return data == null ? false : data.getBoolean(SignInJob.REMEMBER); // } public Properties getData() { return data; } public void aboutToRun(IJobChangeEvent event) { } public void awake(IJobChangeEvent event) { } public void done(IJobChangeEvent event) { Job job = event.getJob(); job.removeJobChangeListener(this); if (job == signInJob) { signInJob = null; final IStatus result = event.getResult(); if (result.getSeverity() == IStatus.OK) { IDataStore resultData = ((InternalSignInJob) job).getData(); data.putAll(resultData.toMap()); getShell().getDisplay().asyncExec(new Runnable() { public void run() { setReturnCode(OK); doClose(); } }); } else { getShell().getDisplay().asyncExec(new Runnable() { public void run() { setErrorMessage(result.getMessage()); changeButton(IDialogConstants.OK_ID, true, Messages.SignInDialog_SignIn_text); for (Integer buttonId : buttonIds) { changeButton(buttonId.intValue(), true, null); } } }); } } } public void running(IJobChangeEvent event) { } public void scheduled(IJobChangeEvent event) { } public void sleeping(IJobChangeEvent event) { } public void setErrorMessage(String errorMessage) { this.errorMessage = errorMessage; if (errorLabel == null || errorLabel.isDisposed()) return; Composite stack = messageArea.getParent(); StackLayout layout = (StackLayout) stack.getLayout(); if (errorMessage == null) { layout.topControl = messageArea; messageArea.setVisible(true); errorMessageArea.setVisible(false); } else { errorLabel.setText(errorMessage); layout.topControl = errorMessageArea; messageArea.setVisible(false); errorMessageArea.setVisible(true); } stack.layout(); } }