com.zimbra.cs.service.formatter.HtmlFormatter.java Source code

Java tutorial

Introduction

Here is the source code for com.zimbra.cs.service.formatter.HtmlFormatter.java

Source

/*
 * ***** BEGIN LICENSE BLOCK *****
 * Zimbra Collaboration Suite Server
 * Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2016 Synacor, Inc.
 *
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software Foundation,
 * version 2 of the License.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License along with this program.
 * If not, see <https://www.gnu.org/licenses/>.
 * ***** END LICENSE BLOCK *****
 */
package com.zimbra.cs.service.formatter;

import java.io.IOException;
import java.util.Enumeration;

import javax.servlet.RequestDispatcher;
import javax.servlet.Servlet;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;

import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.GetMethod;

import com.zimbra.common.httpclient.HttpClientUtil;
import com.zimbra.common.mailbox.Color;
import com.zimbra.common.service.ServiceException;
import com.zimbra.common.util.ByteUtil;
import com.zimbra.common.util.HttpUtil;
import com.zimbra.common.util.Pair;
import com.zimbra.common.util.WebSplitUtil;
import com.zimbra.common.util.ZimbraHttpConnectionManager;
import com.zimbra.cs.account.Account;
import com.zimbra.cs.account.AuthToken;
import com.zimbra.cs.account.AuthTokenException;
import com.zimbra.cs.account.GuestAccount;
import com.zimbra.cs.account.Provisioning;
import com.zimbra.cs.mailbox.Folder;
import com.zimbra.cs.mailbox.MailItem;
import com.zimbra.cs.mailbox.Mountpoint;
import com.zimbra.cs.service.AuthProvider;
import com.zimbra.cs.service.UserServlet;
import com.zimbra.cs.service.UserServlet.HttpInputStream;
import com.zimbra.cs.service.UserServletContext;
import com.zimbra.cs.service.UserServletException;
import com.zimbra.cs.service.formatter.FormatterFactory.FormatType;

public class HtmlFormatter extends Formatter {

    private static final String PATH_MAIN_CONTEXT = "/zimbra";
    private static final String PATH_JSP_REST_PAGE = "/h/rest";
    private static final long AUTH_EXPIRATION = 60L * 60L * 1000L;

    private static final String ATTR_REQUEST_URI = "zimbra_request_uri";

    private static final String ATTR_INTERNAL_DISPATCH = "zimbra_internal_dispatch";
    private static final String ATTR_AUTH_TOKEN = "zimbra_authToken";
    private static final String ATTR_CSRF_ENABLED = "zimbra_csrfEnabled";
    private static final String ATTR_TARGET_ACCOUNT_NAME = "zimbra_target_account_name";
    private static final String ATTR_TARGET_ACCOUNT_ID = "zimbra_target_account_id";
    private static final String ATTR_TARGET_ITEM_ID = "zimbra_target_item_id";
    private static final String ATTR_TARGET_ITEM_TYPE = "zimbra_target_item_type";
    private static final String ATTR_TARGET_ITEM_COLOR = "zimbra_target_item_color";
    private static final String ATTR_TARGET_ITEM_VIEW = "zimbra_target_item_view";
    private static final String ATTR_TARGET_ITEM_PATH = "zimbra_target_item_path";
    private static final String ATTR_TARGET_ITEM_NAME = "zimbra_target_item_name";

    private static final String ATTR_TARGET_ACCOUNT_PREF_TIME_ZONE = "zimbra_target_account_prefTimeZoneId";
    private static final String ATTR_TARGET_ACCOUNT_PREF_SKIN = "zimbra_target_account_prefSkin";
    private static final String ATTR_TARGET_ACCOUNT_PREF_LOCALE = "zimbra_target_account_prefLocale";
    private static final String ATTR_TARGET_ACCOUNT_PREF_CALENDAR_FIRST_DAY_OF_WEEK = "zimbra_target_account_prefCalendarFirstDayOfWeek";
    private static final String ATTR_TARGET_ACCOUNT_PREF_CALENDAR_DAY_HOUR_START = "zimbra_target_account_prefCalendarDayHourStart";
    private static final String ATTR_TARGET_ACCOUNT_PREF_CALENDAR_DAY_HOUR_END = "zimbra_target_account_prefCalendarDayHourEnd";

    @Override
    public void formatCallback(UserServletContext context)
            throws UserServletException, ServiceException, IOException, ServletException {
        dispatchJspRest(context.getServlet(), context);
    }

    @Override
    public FormatType getType() {
        return FormatType.HTML;
    }

    static void dispatchJspRest(Servlet servlet, UserServletContext context)
            throws ServiceException, ServletException, IOException {
        AuthToken auth = null;
        long expiration = System.currentTimeMillis() + AUTH_EXPIRATION;
        if (context.basicAuthHappened) {
            Account acc = context.getAuthAccount();
            if (acc instanceof GuestAccount) {
                auth = AuthToken.getAuthToken(acc.getId(), acc.getName(), null, ((GuestAccount) acc).getDigest(),
                        expiration);
            } else {
                auth = AuthProvider.getAuthToken(context.getAuthAccount(), expiration);
            }
        } else if (context.cookieAuthHappened) {
            auth = UserServlet.getAuthTokenFromCookie(context.req, context.resp, true);
        } else {
            auth = AuthToken.getAuthToken(GuestAccount.GUID_PUBLIC, null, null, null, expiration);
        }
        if (auth != null && context.targetAccount != null && context.targetAccount != context.getAuthAccount()) {
            auth.setProxyAuthToken(
                    Provisioning.getInstance().getProxyAuthToken(context.targetAccount.getId(), null));
        }
        String authString = null;
        try {
            if (auth != null)
                authString = auth.getEncoded();
        } catch (AuthTokenException e) {
            throw new ServletException("error generating the authToken", e);
        }

        Account targetAccount = context.targetAccount;
        MailItem targetItem = context.target;
        String uri = (String) context.req.getAttribute("requestedPath");

        if (targetItem instanceof Mountpoint
                && ((Mountpoint) targetItem).getDefaultView() != MailItem.Type.APPOINTMENT) {
            Mountpoint mp = (Mountpoint) targetItem;
            Provisioning prov = Provisioning.getInstance();
            targetAccount = prov.getAccountById(mp.getOwnerId());
            Pair<Header[], HttpInputStream> remoteItem = UserServlet.getRemoteResourceAsStream(
                    (auth == null) ? null : auth.toZAuthToken(), mp.getTarget(), context.extraPath);
            remoteItem.getSecond().close();
            String remoteItemId = null;
            String remoteItemType = null;
            String remoteItemName = null;
            String remoteItemPath = null;
            for (Header h : remoteItem.getFirst())
                if (h.getName().compareToIgnoreCase("X-Zimbra-ItemId") == 0)
                    remoteItemId = h.getValue();
                else if (h.getName().compareToIgnoreCase("X-Zimbra-ItemType") == 0)
                    remoteItemType = h.getValue();
                else if (h.getName().compareToIgnoreCase("X-Zimbra-ItemName") == 0)
                    remoteItemName = h.getValue();
                else if (h.getName().compareToIgnoreCase("X-Zimbra-ItemPath") == 0)
                    remoteItemPath = h.getValue();

            context.req.setAttribute(ATTR_TARGET_ITEM_ID, remoteItemId);
            context.req.setAttribute(ATTR_TARGET_ITEM_TYPE, remoteItemType);
            context.req.setAttribute(ATTR_TARGET_ITEM_NAME, remoteItemName);
            context.req.setAttribute(ATTR_TARGET_ITEM_PATH, remoteItemPath);
            context.req.setAttribute(ATTR_TARGET_ITEM_COLOR, mp.getColor());
            context.req.setAttribute(ATTR_TARGET_ITEM_VIEW, mp.getDefaultView().toByte());
            targetItem = null;
        }

        context.req.setAttribute(ATTR_INTERNAL_DISPATCH, "yes");
        context.req.setAttribute(ATTR_REQUEST_URI, uri != null ? uri : context.req.getRequestURI());
        context.req.setAttribute(ATTR_AUTH_TOKEN, authString);
        context.req.setAttribute(ATTR_CSRF_ENABLED, auth.isCsrfTokenEnabled());
        if (targetAccount != null) {
            context.req.setAttribute(ATTR_TARGET_ACCOUNT_NAME, targetAccount.getName());
            context.req.setAttribute(ATTR_TARGET_ACCOUNT_ID, targetAccount.getId());
            context.req.setAttribute(ATTR_TARGET_ACCOUNT_PREF_TIME_ZONE,
                    targetAccount.getAttr(Provisioning.A_zimbraPrefTimeZoneId));
            context.req.setAttribute(ATTR_TARGET_ACCOUNT_PREF_SKIN,
                    targetAccount.getAttr(Provisioning.A_zimbraPrefSkin));
            context.req.setAttribute(ATTR_TARGET_ACCOUNT_PREF_LOCALE,
                    targetAccount.getAttr(Provisioning.A_zimbraPrefLocale));
            context.req.setAttribute(ATTR_TARGET_ACCOUNT_PREF_CALENDAR_FIRST_DAY_OF_WEEK,
                    targetAccount.getAttr(Provisioning.A_zimbraPrefCalendarFirstDayOfWeek));
            context.req.setAttribute(ATTR_TARGET_ACCOUNT_PREF_CALENDAR_DAY_HOUR_START,
                    targetAccount.getAttr(Provisioning.A_zimbraPrefCalendarDayHourStart));
            context.req.setAttribute(ATTR_TARGET_ACCOUNT_PREF_CALENDAR_DAY_HOUR_END,
                    targetAccount.getAttr(Provisioning.A_zimbraPrefCalendarDayHourEnd));
        } else {
            // Useful when faking results - e.g. FREEBUSY html view for non-existent account
            if (context.fakeTarget != null) {
                context.req.setAttribute(ATTR_TARGET_ACCOUNT_NAME, context.fakeTarget.getAccount());
            }
            com.zimbra.cs.account.Cos defaultCos = Provisioning.getInstance()
                    .get(com.zimbra.common.account.Key.CosBy.name, Provisioning.DEFAULT_COS_NAME);
            context.req.setAttribute(ATTR_TARGET_ACCOUNT_PREF_TIME_ZONE,
                    defaultCos.getAttr(Provisioning.A_zimbraPrefTimeZoneId));
            context.req.setAttribute(ATTR_TARGET_ACCOUNT_PREF_SKIN,
                    defaultCos.getAttr(Provisioning.A_zimbraPrefSkin));
            context.req.setAttribute(ATTR_TARGET_ACCOUNT_PREF_LOCALE,
                    defaultCos.getAttr(Provisioning.A_zimbraPrefLocale));
            context.req.setAttribute(ATTR_TARGET_ACCOUNT_PREF_CALENDAR_FIRST_DAY_OF_WEEK,
                    defaultCos.getAttr(Provisioning.A_zimbraPrefCalendarFirstDayOfWeek));
            context.req.setAttribute(ATTR_TARGET_ACCOUNT_PREF_CALENDAR_DAY_HOUR_START,
                    defaultCos.getAttr(Provisioning.A_zimbraPrefCalendarDayHourStart));
            context.req.setAttribute(ATTR_TARGET_ACCOUNT_PREF_CALENDAR_DAY_HOUR_END,
                    defaultCos.getAttr(Provisioning.A_zimbraPrefCalendarDayHourEnd));
        }
        if (targetItem != null) {
            context.req.setAttribute(ATTR_TARGET_ITEM_ID, targetItem.getId());
            context.req.setAttribute(ATTR_TARGET_ITEM_PATH, targetItem.getPath());
            context.req.setAttribute(ATTR_TARGET_ITEM_NAME, targetItem.getName());
            context.req.setAttribute(ATTR_TARGET_ITEM_TYPE, targetItem.getType().toString());

            context.req.setAttribute(ATTR_TARGET_ITEM_COLOR, targetItem.getColor());
            if (targetItem instanceof Folder) {
                context.req.setAttribute(ATTR_TARGET_ITEM_VIEW, ((Folder) targetItem).getDefaultView().toString());
            }
        } else {
            context.req.setAttribute(ATTR_TARGET_ITEM_COLOR, Color.getMappedColor(null));
        }
        if (context.fakeTarget != null) { // Override to avoid address harvesting
            context.req.setAttribute(ATTR_TARGET_ITEM_PATH, context.fakeTarget.getPath());
            context.req.setAttribute(ATTR_TARGET_ITEM_NAME, context.fakeTarget.getName());
        }
        String mailUrl = PATH_MAIN_CONTEXT;
        if (WebSplitUtil.isZimbraServiceSplitEnabled()) {
            mailUrl = Provisioning.getInstance().getLocalServer().getWebClientURL() + PATH_JSP_REST_PAGE;
            HttpClient httpclient = ZimbraHttpConnectionManager.getInternalHttpConnMgr().getDefaultHttpClient();
            /*
             * Retest the code with POST to check whether it works
            PostMethod postMethod = new PostMethod(mailUrl);
            Enumeration<String> attributeNames = context.req.getAttributeNames();
            List<Part> parts = new ArrayList<Part>();
            while(attributeNames.hasMoreElements())
            {
            String attrName = (String) attributeNames.nextElement();
            String attrValue = context.req.getAttribute(attrName).toString();
            Part part = new StringPart(attrName, attrValue);
            parts.add(part);
            }
            postMethod.setRequestEntity(new MultipartRequestEntity(parts.toArray(new Part[0]), new HttpMethodParams()));
                
            HttpClientUtil.executeMethod(httpclient, postMethod);
            ByteUtil.copy(postMethod.getResponseBodyAsStream(), true, context.resp.getOutputStream(), true);
            */

            Enumeration<String> attributeNames = context.req.getAttributeNames();
            StringBuilder sb = new StringBuilder(mailUrl);
            sb.append("?");
            while (attributeNames.hasMoreElements()) {
                String attrName = attributeNames.nextElement();
                String attrValue = context.req.getAttribute(attrName).toString();
                sb.append(attrName).append("=").append(HttpUtil.urlEscape(attrValue)).append("&");
            }
            GetMethod postMethod = new GetMethod(sb.toString());

            HttpClientUtil.executeMethod(httpclient, postMethod);
            ByteUtil.copy(postMethod.getResponseBodyAsStream(), true, context.resp.getOutputStream(), false);
        } else {
            try {
                mailUrl = Provisioning.getInstance().getLocalServer().getMailURL();
            } catch (Exception e) {
            }
            ServletContext targetContext = servlet.getServletConfig().getServletContext().getContext(mailUrl);
            RequestDispatcher dispatcher = targetContext.getRequestDispatcher(PATH_JSP_REST_PAGE);
            dispatcher.forward(context.req, context.resp);
        }
    }
}