blob: c9e816d41a4156fe839b175b654aae248dc7dee8 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004, 2010 Tasktop Technologies and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Tasktop Technologies - initial API and implementation
* Frank Becker - fixes for bug 165072
* Red Hat Inc. - fixes for bug 259291
*******************************************************************************/
package org.eclipse.mylyn.internal.bugzilla.core;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.Reader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.Proxy;
import java.net.URL;
import java.net.URLDecoder;
import java.nio.charset.Charset;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import javax.security.auth.login.LoginException;
import javax.swing.text.html.HTML.Tag;
import org.apache.commons.httpclient.Cookie;
import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HostConfiguration;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpMethodBase;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.RedirectException;
import org.apache.commons.httpclient.URI;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.HeadMethod;
import org.apache.commons.httpclient.methods.multipart.FilePart;
import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity;
import org.apache.commons.httpclient.methods.multipart.Part;
import org.apache.commons.httpclient.methods.multipart.PartBase;
import org.apache.commons.httpclient.methods.multipart.StringPart;
import org.apache.commons.httpclient.params.HttpMethodParams;
import org.apache.commons.httpclient.util.DateParseException;
import org.apache.commons.httpclient.util.DateUtil;
import org.apache.xmlrpc.XmlRpcException;
import org.eclipse.core.net.proxy.IProxyData;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.mylyn.commons.core.StatusHandler;
import org.eclipse.mylyn.commons.net.AbstractWebLocation;
import org.eclipse.mylyn.commons.net.AuthenticationCredentials;
import org.eclipse.mylyn.commons.net.AuthenticationType;
import org.eclipse.mylyn.commons.net.HtmlStreamTokenizer;
import org.eclipse.mylyn.commons.net.HtmlStreamTokenizer.Token;
import org.eclipse.mylyn.commons.net.HtmlTag;
import org.eclipse.mylyn.commons.net.Policy;
import org.eclipse.mylyn.commons.net.WebLocation;
import org.eclipse.mylyn.commons.net.WebUtil;
import org.eclipse.mylyn.internal.bugzilla.core.history.BugzillaTaskHistoryParser;
import org.eclipse.mylyn.internal.bugzilla.core.history.TaskHistory;
import org.eclipse.mylyn.internal.bugzilla.core.service.BugzillaXmlRpcClient;
import org.eclipse.mylyn.tasks.core.IRepositoryQuery;
import org.eclipse.mylyn.tasks.core.RepositoryResponse;
import org.eclipse.mylyn.tasks.core.RepositoryResponse.ResponseKind;
import org.eclipse.mylyn.tasks.core.RepositoryStatus;
import org.eclipse.mylyn.tasks.core.TaskRepository;
import org.eclipse.mylyn.tasks.core.data.AbstractTaskAttachmentSource;
import org.eclipse.mylyn.tasks.core.data.TaskAttachmentMapper;
import org.eclipse.mylyn.tasks.core.data.TaskAttachmentPartSource;
import org.eclipse.mylyn.tasks.core.data.TaskAttribute;
import org.eclipse.mylyn.tasks.core.data.TaskAttributeMapper;
import org.eclipse.mylyn.tasks.core.data.TaskData;
import org.eclipse.mylyn.tasks.core.data.TaskDataCollector;
/**
* @author Mik Kersten
* @author Rob Elves
* @author Steffen Pingel
*/
public class BugzillaClient {
private static final String UNKNOWN_REPOSITORY_ERROR = "An unknown repository error has occurred: "; //$NON-NLS-1$
private static final String COOKIE_BUGZILLA_LOGIN = "Bugzilla_login"; //$NON-NLS-1$
protected static final String USER_AGENT = "BugzillaConnector"; //$NON-NLS-1$
private static final int MAX_RETRIEVED_PER_QUERY = 50;
private static final String QUERY_DELIMITER = "?"; //$NON-NLS-1$
private static final String KEY_ID = "id"; //$NON-NLS-1$
private static final String VAL_TRUE = "true"; //$NON-NLS-1$
private static final String KEY_CC = "cc"; //$NON-NLS-1$
private static final String POST_BUG_CGI = "/post_bug.cgi"; //$NON-NLS-1$
private static final String PROCESS_BUG_CGI = "/process_bug.cgi"; //$NON-NLS-1$
private static final String PROCESS_ATTACHMENT_CGI = "/attachment.cgi"; //$NON-NLS-1$
public static final int WRAP_LENGTH = 80;
private static final String VAL_PROCESS_BUG = "process_bug"; //$NON-NLS-1$
private static final String KEY_FORM_NAME = "form_name"; //$NON-NLS-1$
private static final String VAL_NONE = "none"; //$NON-NLS-1$
private static final String KEY_KNOB = "knob"; //$NON-NLS-1$
// TODO change to BugzillaReportElement.ADD_COMMENT
private static final String KEY_COMMENT = "comment"; //$NON-NLS-1$
private static final String KEY_SHORT_DESC = "short_desc"; //$NON-NLS-1$
private static final String VALUE_CONTENTTYPEMETHOD_MANUAL = "manual"; //$NON-NLS-1$
private static final String VALUE_ISPATCH = "1"; //$NON-NLS-1$
private static final String VALUE_ACTION_INSERT = "insert"; //$NON-NLS-1$
private static final String ATTRIBUTE_CONTENTTYPEENTRY = "contenttypeentry"; //$NON-NLS-1$
private static final String ATTRIBUTE_CONTENTTYPEMETHOD = "contenttypemethod"; //$NON-NLS-1$
private static final String ATTRIBUTE_ISPATCH = "ispatch"; //$NON-NLS-1$
private static final String CONTENT_TYPE_APP_RDF_XML = "application/rdf+xml"; //$NON-NLS-1$
private static final String CONTENT_TYPE_APP_XML = "application/xml"; //$NON-NLS-1$
private static final String CONTENT_TYPE_TEXT_XML = "text/xml"; //$NON-NLS-1$
private static final String[] VALID_CONFIG_CONTENT_TYPES = { CONTENT_TYPE_APP_RDF_XML, CONTENT_TYPE_APP_XML,
CONTENT_TYPE_TEXT_XML };
private static final String ATTR_CHARSET = "charset"; //$NON-NLS-1$
protected Proxy proxy = Proxy.NO_PROXY;
protected URL repositoryUrl;
protected String characterEncoding;
private boolean loggedIn;
private final Map<String, String> configParameters;
private final HttpClient httpClient = new HttpClient(WebUtil.getConnectionManager());
private boolean lastModifiedSupported = true;
private final BugzillaLanguageSettings bugzillaLanguageSettings;
private RepositoryConfiguration repositoryConfiguration;
private HostConfiguration hostConfiguration;
private final AbstractWebLocation location;
private final BugzillaRepositoryConnector connector;
private BugzillaXmlRpcClient xmlRpcClient = null;
public BugzillaClient(AbstractWebLocation location, String characterEncoding, Map<String, String> configParameters,
BugzillaLanguageSettings languageSettings, BugzillaRepositoryConnector connector)
throws MalformedURLException {
this.repositoryUrl = new URL(location.getUrl());
this.location = location;
this.characterEncoding = characterEncoding;
this.configParameters = configParameters;
this.bugzillaLanguageSettings = languageSettings;
this.connector = connector;
this.proxy = location.getProxyForHost(location.getUrl(), IProxyData.HTTP_PROXY_TYPE);
WebUtil.configureHttpClient(httpClient, USER_AGENT);
}
public BugzillaClient(AbstractWebLocation location, TaskRepository taskRepository,
BugzillaRepositoryConnector connector) throws MalformedURLException {
this(location, taskRepository.getCharacterEncoding(), taskRepository.getProperties(),
getLanguageSettings(taskRepository), connector);
}
private static BugzillaLanguageSettings getLanguageSettings(TaskRepository taskRepository) {
String language = taskRepository.getProperty(IBugzillaConstants.BUGZILLA_LANGUAGE_SETTING);
if (language == null || language.equals("")) { //$NON-NLS-1$
language = IBugzillaConstants.DEFAULT_LANG;
}
return BugzillaRepositoryConnector.getLanguageSetting(language);
}
public void validate(IProgressMonitor monitor) throws IOException, CoreException {
monitor = Policy.monitorFor(monitor);
GzipGetMethod method = null;
try {
logout(monitor);
method = getConnect(repositoryUrl + "/", monitor); //$NON-NLS-1$
} finally {
if (method != null) {
WebUtil.releaseConnection(method, monitor);
}
}
CustomTransitionManager validTransitions = new CustomTransitionManager();
String transitionsFileName = configParameters.get(IBugzillaConstants.BUGZILLA_DESCRIPTOR_FILE);
if (transitionsFileName != null && !transitionsFileName.equals("")) { //$NON-NLS-1$
if (!validTransitions.parse(transitionsFileName)) {
throw new CoreException(new Status(IStatus.WARNING, BugzillaCorePlugin.ID_PLUGIN,
"Invalide Transition File Content")); //$NON-NLS-1$
}
}
if (Boolean.parseBoolean(configParameters.get(IBugzillaConstants.BUGZILLA_USE_XMLRPC))) {
getXmlRpcClient();
int uID = -1;
try {
uID = xmlRpcClient.login(monitor);
if (uID == -1) {
throw new CoreException(new Status(IStatus.WARNING, BugzillaCorePlugin.ID_PLUGIN,
"XMLRPC user could not login")); //$NON-NLS-1$
}
} catch (XmlRpcException e) {
throw new CoreException(new Status(IStatus.WARNING, BugzillaCorePlugin.ID_PLUGIN,
"XMLRPC is not installed")); //$NON-NLS-1$
}
}
}
protected boolean hasAuthenticationCredentials() {
AuthenticationCredentials credentials = location.getCredentials(AuthenticationType.REPOSITORY);
return (credentials != null && credentials.getUserName() != null && credentials.getUserName().length() > 0);
}
protected boolean hasHTTPAuthenticationCredentials() {
AuthenticationCredentials credentials = location.getCredentials(AuthenticationType.HTTP);
return (credentials != null && credentials.getUserName() != null && credentials.getUserName().length() > 0);
}
private GzipGetMethod getConnect(String serverURL, IProgressMonitor monitor) throws IOException, CoreException {
return connectInternal(serverURL, false, monitor, null);
}
protected GzipGetMethod getConnectGzip(String serverURL, IProgressMonitor monitor) throws IOException,
CoreException {
return getConnectGzip(serverURL, monitor, null);
}
/**
* in order to provide an even better solution for bug 196056 the size of the bugzilla configuration downloaded must
* be reduced. By using a cached version of the config.cgi this can reduce traffic considerably:
* http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.phoenix/infra-scripts/bugzilla/?root=Technology_Project
*
* @param serverURL
* @return a GetMethod with possibly gzip encoded response body, so caller MUST check with
* "gzip".equals(method.getResponseHeader("Content-encoding") or use the utility method
* getResponseBodyAsUnzippedStream().
* @throws IOException
* @throws CoreException
*/
protected GzipGetMethod getConnectGzip(String serverURL, IProgressMonitor monitor, String eTagValue)
throws IOException, CoreException {
return connectInternal(serverURL, true, monitor, eTagValue);
}
private GzipGetMethod connectInternal(String requestURL, boolean gzip, IProgressMonitor monitor, String eTagValue)
throws IOException, CoreException {
monitor = Policy.monitorFor(monitor);
hostConfiguration = WebUtil.createHostConfiguration(httpClient, location, monitor);
for (int attempt = 0; attempt < 2; attempt++) {
// force authentication
authenticate(monitor);
GzipGetMethod getMethod = new GzipGetMethod(WebUtil.getRequestPath(requestURL), gzip);
if (requestURL.contains(QUERY_DELIMITER)) {
getMethod.setQueryString(requestURL.substring(requestURL.indexOf(QUERY_DELIMITER)));
}
getMethod.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=" //$NON-NLS-1$ //$NON-NLS-2$
+ getCharacterEncoding());
if (eTagValue != null && eTagValue.compareTo("") != 0) { //$NON-NLS-1$
getMethod.setRequestHeader("If-None-Match", eTagValue); //$NON-NLS-1$
}
// Resolves bug#195113
httpClient.getParams().setParameter("http.protocol.single-cookie-header", true); //$NON-NLS-1$
// WARNING!! Setting browser compatibility breaks Bugzilla
// authentication
// getMethod.getParams().setCookiePolicy(CookiePolicy.BROWSER_COMPATIBILITY);
// getMethod.getParams().setCookiePolicy(CookiePolicy.RFC_2109);
getMethod.setDoAuthentication(true);
int code;
try {
code = WebUtil.execute(httpClient, hostConfiguration, getMethod, monitor);
} catch (IOException e) {
WebUtil.releaseConnection(getMethod, monitor);
throw new CoreException(new BugzillaStatus(IStatus.ERROR, BugzillaCorePlugin.ID_PLUGIN,
RepositoryStatus.ERROR_IO, repositoryUrl.toString(), e));
}
if (code == HttpURLConnection.HTTP_OK) {
return getMethod;
} else {
WebUtil.releaseConnection(getMethod, monitor);
if (code == HttpURLConnection.HTTP_NOT_MODIFIED) {
throw new CoreException(new Status(IStatus.WARNING, BugzillaCorePlugin.ID_PLUGIN, "Not changed")); //$NON-NLS-1$
} else if (code == HttpURLConnection.HTTP_UNAUTHORIZED || code == HttpURLConnection.HTTP_FORBIDDEN) {
// login or reauthenticate due to an expired session
loggedIn = false;
authenticate(monitor);
} else if (code == HttpURLConnection.HTTP_PROXY_AUTH) {
loggedIn = false;
throw new CoreException(new BugzillaStatus(IStatus.ERROR, BugzillaCorePlugin.ID_PLUGIN,
RepositoryStatus.ERROR_REPOSITORY_LOGIN, repositoryUrl.toString(),
"Proxy authentication required")); //$NON-NLS-1$
} else {
throw new CoreException(new BugzillaStatus(IStatus.ERROR, BugzillaCorePlugin.ID_PLUGIN,
RepositoryStatus.ERROR_NETWORK, "Http error: " + HttpStatus.getStatusText(code))); //$NON-NLS-1$
}
}
}
throw new CoreException(new BugzillaStatus(IStatus.ERROR, BugzillaCorePlugin.ID_PLUGIN,
RepositoryStatus.ERROR_INTERNAL, "All connection attempts to " + repositoryUrl.toString() //$NON-NLS-1$
+ " failed. Please verify connection and authentication information.")); //$NON-NLS-1$
}
public void logout(IProgressMonitor monitor) throws IOException, CoreException {
monitor = Policy.monitorFor(monitor);
String loginUrl = repositoryUrl + "/relogin.cgi"; //$NON-NLS-1$
GzipGetMethod method = null;
try {
method = getConnect(loginUrl, monitor);
loggedIn = false;
httpClient.getState().clearCookies();
} finally {
if (method != null) {
WebUtil.releaseConnection(method, monitor);
}
}
}
protected InputStream getResponseStream(HttpMethodBase method, IProgressMonitor monitor) throws IOException {
InputStream in = WebUtil.getResponseBodyAsStream(method, monitor);
if (isZippedReply(method)) {
in = new java.util.zip.GZIPInputStream(in);
}
return in;
}
private boolean isZippedReply(HttpMethodBase method) {
// content-encoding:gzip can be set by a dedicated perl script or mod_gzip
boolean zipped = (null != method.getResponseHeader("Content-encoding") && method.getResponseHeader( //$NON-NLS-1$
"Content-encoding").getValue().equals(IBugzillaConstants.CONTENT_ENCODING_GZIP)) //$NON-NLS-1$
||
// content-type: application/x-gzip can be set by any apache after 302 redirect, based on .gz suffix
(null != method.getResponseHeader("Content-Type") && method.getResponseHeader("Content-Type") //$NON-NLS-1$ //$NON-NLS-2$
.getValue()
.equals("application/x-gzip")); //$NON-NLS-1$
return zipped;
}
public void authenticate(IProgressMonitor monitor) throws CoreException {
if (loggedIn || (!hasAuthenticationCredentials() && !hasHTTPAuthenticationCredentials())) {
return;
}
monitor = Policy.monitorFor(monitor);
GzipPostMethod postMethod = null;
try {
hostConfiguration = WebUtil.createHostConfiguration(httpClient, location, monitor);
NameValuePair[] formData = new NameValuePair[2];
AuthenticationCredentials credentials = location.getCredentials(AuthenticationType.REPOSITORY);
AuthenticationCredentials httpAuthCredentials = location.getCredentials(AuthenticationType.HTTP);
if (credentials == null && httpAuthCredentials == null) {
loggedIn = false;
throw new CoreException(new BugzillaStatus(IStatus.ERROR, BugzillaCorePlugin.ID_PLUGIN,
RepositoryStatus.ERROR_REPOSITORY_LOGIN, repositoryUrl.toString(),
"Authentication credentials from location missing.")); //$NON-NLS-1$
}
if (credentials != null) {
String password = credentials.getPassword();
if ("".equals(password) && !hasHTTPAuthenticationCredentials()) { //$NON-NLS-1$
loggedIn = false;
throw new CoreException(new BugzillaStatus(IStatus.ERROR, BugzillaCorePlugin.ID_PLUGIN,
RepositoryStatus.ERROR_EMPTY_PASSWORD, repositoryUrl.toString(),
"Empty password not allowed for Authentication credentials.")); //$NON-NLS-1$
}
formData[0] = new NameValuePair(IBugzillaConstants.POST_INPUT_BUGZILLA_LOGIN, credentials.getUserName());
formData[1] = new NameValuePair(IBugzillaConstants.POST_INPUT_BUGZILLA_PASSWORD,
credentials.getPassword());
}
postMethod = new GzipPostMethod(WebUtil.getRequestPath(repositoryUrl.toString()
+ IBugzillaConstants.URL_POST_LOGIN), true);
postMethod.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=" //$NON-NLS-1$ //$NON-NLS-2$
+ getCharacterEncoding());
if (credentials != null) {
postMethod.setRequestBody(formData);
}
postMethod.setDoAuthentication(true);
postMethod.setFollowRedirects(false);
httpClient.getState().clearCookies();
if (httpAuthCredentials != null && httpAuthCredentials.getUserName() != null
&& httpAuthCredentials.getUserName().length() > 0) {
httpClient.getParams().setAuthenticationPreemptive(true);
}
int code = WebUtil.execute(httpClient, hostConfiguration, postMethod, monitor);
if (code == HttpURLConnection.HTTP_UNAUTHORIZED || code == HttpURLConnection.HTTP_FORBIDDEN) {
loggedIn = false;
WebUtil.releaseConnection(postMethod, monitor);
throw new CoreException(new BugzillaStatus(IStatus.ERROR, BugzillaCorePlugin.ID_PLUGIN,
RepositoryStatus.ERROR_REPOSITORY_LOGIN, repositoryUrl.toString(),
"HTTP authentication failed.")); //$NON-NLS-1$
} else if (code == HttpURLConnection.HTTP_PROXY_AUTH) {
loggedIn = false;
WebUtil.releaseConnection(postMethod, monitor);
throw new CoreException(new BugzillaStatus(IStatus.ERROR, BugzillaCorePlugin.ID_PLUGIN,
RepositoryStatus.ERROR_REPOSITORY_LOGIN, repositoryUrl.toString(),
"Proxy authentication required")); //$NON-NLS-1$
} else if (code != HttpURLConnection.HTTP_OK) {
loggedIn = false;
WebUtil.releaseConnection(postMethod, monitor);
throw new CoreException(new BugzillaStatus(IStatus.ERROR, BugzillaCorePlugin.ID_PLUGIN,
RepositoryStatus.ERROR_NETWORK, "Http error: " + HttpStatus.getStatusText(code))); //$NON-NLS-1$
}
if (httpAuthCredentials != null && httpAuthCredentials.getUserName() != null
&& httpAuthCredentials.getUserName().length() > 0) {
// If httpAuthCredentials are used HttpURLConnection.HTTP_UNAUTHORIZED when the credentials are invalide so we
// not need to test the cookies.
// see bug 305267 or https://bugzilla.mozilla.org/show_bug.cgi?id=385606
loggedIn = true;
InputStream inputStream = getResponseStream(postMethod, monitor);
try {
BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, getCharacterEncoding()));
try {
String errorMessage = extractErrorMessage(in);
if (errorMessage != null) {
loggedIn = false;
throw new CoreException(new BugzillaStatus(IStatus.ERROR, BugzillaCorePlugin.ID_PLUGIN,
RepositoryStatus.ERROR_REPOSITORY_LOGIN, repositoryUrl.toString(), errorMessage));
}
} finally {
inputStream.close();
}
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else if (hasAuthenticationCredentials()) {
for (Cookie cookie : httpClient.getState().getCookies()) {
if (cookie.getName().equals(COOKIE_BUGZILLA_LOGIN)) {
loggedIn = true;
break;
}
}
if (!loggedIn) {
InputStream input = getResponseStream(postMethod, monitor);
try {
parseHtmlError(input);
} finally {
input.close();
}
}
} else {
// anonymous login
loggedIn = true;
}
} catch (IOException e) {
throw new CoreException(new BugzillaStatus(IStatus.ERROR, BugzillaCorePlugin.ID_PLUGIN,
RepositoryStatus.ERROR_IO, repositoryUrl.toString(), e));
} finally {
if (postMethod != null) {
WebUtil.releaseConnection(postMethod, monitor);
}
httpClient.getParams().setAuthenticationPreemptive(false);
}
}
private String extractErrorMessage(Reader responseContent) throws IOException, ParseException {
HtmlStreamTokenizer tokenizer = new HtmlStreamTokenizer(responseContent, null);
for (Token token = tokenizer.nextToken(); token.getType() != Token.EOF; token = tokenizer.nextToken()) {
if (isErrorMessageToken(token)) {
return computeErrorMessage(tokenizer, token);
}
}
return null;
}
private static String computeErrorMessage(HtmlStreamTokenizer tokenizer, Token token) throws IOException,
ParseException {
int tagDepth = 0;
String errorMessage = ""; //$NON-NLS-1$
for (token = tokenizer.nextToken(); token.getType() != Token.EOF; token = tokenizer.nextToken()) {
if (token.getType() == Token.TAG) {
HtmlTag htmlTag = (HtmlTag) token.getValue();
if (htmlTag.isEndTag()) {
--tagDepth;
if (tagDepth < 0) {
break;
}
} else {
++tagDepth;
}
} else {
errorMessage += token.toString();
}
}
errorMessage = errorMessage.replaceAll("\\s+", " "); //$NON-NLS-1$//$NON-NLS-2$
return errorMessage;
}
private boolean isErrorMessageToken(Token token) {
if (token.getType() == Token.TAG && ((HtmlTag) (token.getValue())).getTagType() == Tag.TD
&& !((HtmlTag) (token.getValue())).isEndTag()) {
HtmlTag ta = ((HtmlTag) token.getValue());
String st = ta.getAttribute("id"); //$NON-NLS-1$
if (st != null && st.equals("error_msg")) { //$NON-NLS-1$
return true;
}
}
return false;
}
public boolean getSearchHits(IRepositoryQuery query, TaskDataCollector collector, TaskAttributeMapper mapper,
IProgressMonitor monitor) throws IOException, CoreException {
HttpMethodBase postMethod = null;
try {
authenticate(new SubProgressMonitor(monitor, 1));
String queryUrl = query.getUrl();
int start = queryUrl.indexOf('?');
List<NameValuePair> pairs = new ArrayList<NameValuePair>();
if (start != -1) {
queryUrl = queryUrl.substring(start + 1);
String[] result = queryUrl.split("&"); //$NON-NLS-1$
if (result.length > 0) {
for (String string : result) {
String[] nameValue = string.split("="); //$NON-NLS-1$
if (nameValue.length == 1) {
pairs.add(new NameValuePair(nameValue[0].trim(), "")); //$NON-NLS-1$
} else if (nameValue.length == 2 && nameValue[0] != null && nameValue[1] != null) {
//Hack around bugzilla's change of attribute name for comment search field bug#289155
if (nameValue[0].startsWith("long_desc")) { //$NON-NLS-1$
pairs.add(new NameValuePair(nameValue[0].replace("long_desc", "longdesc"), //$NON-NLS-1$ //$NON-NLS-2$
URLDecoder.decode(nameValue[1].trim(), getCharacterEncoding())));
}
pairs.add(new NameValuePair(nameValue[0].trim(), URLDecoder.decode(nameValue[1].trim(),
getCharacterEncoding())));
}
}
}
}
NameValuePair ctypePair = new NameValuePair("ctype", "rdf"); //$NON-NLS-1$ //$NON-NLS-2$
// Test that we don't specify content type twice.
if (!pairs.contains(ctypePair)) {
pairs.add(ctypePair);
}
try {
postMethod = postFormData(IBugzillaConstants.URL_BUGLIST,
pairs.toArray(new NameValuePair[pairs.size()]), monitor);
} catch (RedirectException r) {
// Handle one redirect (Bugzilla 3.4 provides a redirect upon query submission via post)
postMethod = getConnectGzip(r.getMessage(), monitor, null);
}
if (postMethod != null && postMethod.getResponseHeader("Content-Type") != null) { //$NON-NLS-1$
Header responseTypeHeader = postMethod.getResponseHeader("Content-Type"); //$NON-NLS-1$
for (String type : VALID_CONFIG_CONTENT_TYPES) {
if (responseTypeHeader.getValue().toLowerCase(Locale.ENGLISH).contains(type)) {
InputStream stream = getResponseStream(postMethod, monitor);
try {
RepositoryQueryResultsFactory queryFactory = getQueryResultsFactory(stream);
int count = queryFactory.performQuery(repositoryUrl.toString(), collector, mapper,
TaskDataCollector.MAX_HITS);
return count > 0;
} finally {
stream.close();
}
}
}
}
// because html is not a valid config content type it is save to get the response here
parseHtmlError(getResponseStream(postMethod, monitor));
} finally {
if (postMethod != null) {
WebUtil.releaseConnection(postMethod, monitor);
}
}
return false;
}
protected RepositoryQueryResultsFactory getQueryResultsFactory(InputStream stream) {
return new RepositoryQueryResultsFactory(stream, getCharacterEncoding());
}
protected void setupExistingBugAttributes(String serverUrl, TaskData existingReport) {
// ordered list of elements as they appear in UI
// and additional elements that may not appear in the incoming xml
// stream but need to be present for bug submission / not always dirty
// state handling
BugzillaAttribute[] reportElements1 = { BugzillaAttribute.SHORT_DESC, BugzillaAttribute.BUG_STATUS,
BugzillaAttribute.RESOLUTION, BugzillaAttribute.BUG_ID, BugzillaAttribute.REP_PLATFORM,
BugzillaAttribute.PRODUCT, BugzillaAttribute.OP_SYS, BugzillaAttribute.COMPONENT,
BugzillaAttribute.VERSION, BugzillaAttribute.PRIORITY, BugzillaAttribute.BUG_SEVERITY,
BugzillaAttribute.ASSIGNED_TO };
BugzillaAttribute[] reportElements2 = { BugzillaAttribute.REPORTER, BugzillaAttribute.DEPENDSON,
BugzillaAttribute.BLOCKED, BugzillaAttribute.BUG_FILE_LOC, BugzillaAttribute.NEWCC,
BugzillaAttribute.KEYWORDS, BugzillaAttribute.CC, BugzillaAttribute.NEW_COMMENT };
TaskRepository taskRepository = existingReport.getAttributeMapper().getTaskRepository();
for (BugzillaAttribute element : reportElements1) {
BugzillaTaskDataHandler.createAttribute(existingReport, element);
}
BugzillaUtil.addAttributeIfUsed(BugzillaAttribute.TARGET_MILESTONE,
IBugzillaConstants.BUGZILLA_PARAM_USETARGETMILESTONE, taskRepository, existingReport, true);
for (BugzillaAttribute element : reportElements2) {
BugzillaTaskDataHandler.createAttribute(existingReport, element);
}
BugzillaUtil.addAttributeIfUsed(BugzillaAttribute.QA_CONTACT, IBugzillaConstants.BUGZILLA_PARAM_USEQACONTACT,
taskRepository, existingReport, true);
BugzillaUtil.addAttributeIfUsed(BugzillaAttribute.STATUS_WHITEBOARD,
IBugzillaConstants.BUGZILLA_PARAM_USESTATUSWHITEBOARD, taskRepository, existingReport, true);
BugzillaUtil.addAttributeIfUsed(BugzillaAttribute.ALIAS, IBugzillaConstants.BUGZILLA_PARAM_USEBUGALIASES,
taskRepository, existingReport, false);
BugzillaUtil.addAttributeIfUsed(BugzillaAttribute.CLASSIFICATION,
IBugzillaConstants.BUGZILLA_PARAM_USECLASSIFICATION, taskRepository, existingReport, false);
BugzillaUtil.addAttributeIfUsed(BugzillaAttribute.SEE_ALSO, IBugzillaConstants.BUGZILLA_PARAM_USE_SEE_ALSO,
taskRepository, existingReport, false);
if (repositoryConfiguration == null) {
repositoryConfiguration = connector.getRepositoryConfiguration(serverUrl);
}
if (repositoryConfiguration != null) {
for (BugzillaCustomField bugzillaCustomField : repositoryConfiguration.getCustomFields()) {
existingReport.getRoot().createAttribute(bugzillaCustomField.getName());
}
}
}
public static String getBugUrlWithoutLogin(String repositoryUrl, String id) {
String url = repositoryUrl + IBugzillaConstants.URL_GET_SHOW_BUG + id;
return url;
}
public static String getCharsetFromString(String string) {
int charsetStartIndex = string.indexOf(ATTR_CHARSET);
if (charsetStartIndex != -1) {
int charsetEndIndex = string.indexOf("\"", charsetStartIndex); // TODO: //$NON-NLS-1$
// could
// be
// space
// after?
if (charsetEndIndex == -1) {
charsetEndIndex = string.length();
}
String charsetString = string.substring(charsetStartIndex + 8, charsetEndIndex);
if (Charset.availableCharsets().containsKey(charsetString)) {
return charsetString;
}
}
return null;
}
@Deprecated
public RepositoryConfiguration getRepositoryConfiguration(IProgressMonitor monitor) throws IOException,
CoreException {
return getRepositoryConfiguration(monitor, null);
}
public RepositoryConfiguration getRepositoryConfiguration(IProgressMonitor monitor, String eTagValue)
throws IOException, CoreException {
GzipGetMethod method = null;
int attempt = 0;
while (attempt < 2) {
try {
method = getConnectGzip(repositoryUrl + IBugzillaConstants.URL_GET_CONFIG_RDF, monitor, eTagValue);
// provide a solution for bug 196056 by allowing a (cached) gzipped configuration to be sent
// modified to also accept "application/x-gzip" as results from a 302 redirect to a previously gzipped file.
if (method == null) {
throw new IOException("Could not retrieve configuratoin. HttpClient return null method."); //$NON-NLS-1$
}
InputStream stream = getResponseStream(method, monitor);
try {
if (method.getResponseHeader("Content-Type") != null) { //$NON-NLS-1$
Header responseTypeHeader = method.getResponseHeader("Content-Type"); //$NON-NLS-1$
for (String type : VALID_CONFIG_CONTENT_TYPES) {
if (responseTypeHeader.getValue().toLowerCase(Locale.ENGLISH).contains(type)) {
RepositoryConfigurationFactory configFactory = new RepositoryConfigurationFactory(
stream, getCharacterEncoding());
repositoryConfiguration = configFactory.getConfiguration();
Header eTag = method.getResponseHeader("ETag"); //$NON-NLS-1$
if (eTag != null) {
repositoryConfiguration.setETagValue(eTag.getValue());
} else {
repositoryConfiguration.setETagValue(null);
}
Header lastModifiedHeader = method.getResponseHeader("Last-Modified"); //$NON-NLS-1$
if (lastModifiedHeader != null) {
try {
repositoryConfiguration.setLastModifiedHeader(DateUtil.parseDate(lastModifiedHeader.getValue()));
} catch (DateParseException e) {
repositoryConfiguration.setLastModifiedHeader((Date) null);
}
} else {
repositoryConfiguration.setLastModifiedHeader((Date) null);
}
if (repositoryConfiguration != null) {
getXmlRpcClient();
if (xmlRpcClient != null) {
xmlRpcClient.updateConfiguration(monitor, repositoryConfiguration,
configParameters.get(IBugzillaConstants.BUGZILLA_DESCRIPTOR_FILE));
} else {
repositoryConfiguration.setValidTransitions(monitor,
configParameters.get(IBugzillaConstants.BUGZILLA_DESCRIPTOR_FILE), null);
}
if (!repositoryConfiguration.getProducts().isEmpty()) {
repositoryConfiguration.setRepositoryUrl(repositoryUrl.toString());
}
if (!repositoryConfiguration.getProducts().isEmpty()) {
return repositoryConfiguration;
} else {
if (attempt == 0) {
// empty configuration, retry authenticate
loggedIn = false;
break;
} else {
throw new CoreException(
new Status(IStatus.WARNING, BugzillaCorePlugin.ID_PLUGIN,
"No products found in repository configuration. Ensure credentials are valid.")); //$NON-NLS-1$
}
}
}
}
}
}
if (loggedIn) {
parseHtmlError(stream);
return null;
}
} finally {
stream.close();
}
} finally {
attempt++;
if (method != null) {
WebUtil.releaseConnection(method, monitor);
}
}
}
return null;
}
public void getAttachmentData(String attachmentId, OutputStream out, IProgressMonitor monitor) throws IOException,
CoreException {
String url = repositoryUrl + IBugzillaConstants.URL_GET_ATTACHMENT_DOWNLOAD + attachmentId;
GetMethod method = connectInternal(url, false, monitor, null);//getConnectGzip(url, monitor);
try {
int status = WebUtil.execute(httpClient, hostConfiguration, method, monitor);
if (status == HttpStatus.SC_OK) {
//copy the response
InputStream instream = method.getResponseBodyAsStream();
if (instream != null) {
byte[] buffer = new byte[4096];
int len;
while ((len = instream.read(buffer)) > 0) {
out.write(buffer, 0, len);
}
}
} else {
parseHtmlError(method.getResponseBodyAsStream());
}
} catch (IOException e) {
throw e;
} finally {
WebUtil.releaseConnection(method, monitor);
}
}
private String getCharacterEncoding() {
if (repositoryConfiguration != null && repositoryConfiguration.getEncoding() != null
&& repositoryConfiguration.getEncoding().length() > 0) {
// Special case for eclipse.org. See bug#280361 and bug#275102
return repositoryConfiguration.getEncoding();
} else {
return characterEncoding;
}
}
public void postAttachment(String bugReportID, String comment, AbstractTaskAttachmentSource source,
TaskAttribute attachmentAttribute, IProgressMonitor monitor) throws HttpException, IOException,
CoreException {
monitor = Policy.monitorFor(monitor);
String description = source.getDescription();
String contentType = source.getContentType();
String filename = source.getName();
boolean isPatch = false;
if (attachmentAttribute != null) {
TaskAttachmentMapper mapper = TaskAttachmentMapper.createFrom(attachmentAttribute);
if (mapper.getDescription() != null) {
description = mapper.getDescription();
}
if (mapper.getContentType() != null) {
contentType = mapper.getContentType();
}
if (mapper.getFileName() != null) {
filename = mapper.getFileName();
}
if (mapper.isPatch() != null) {
isPatch = mapper.isPatch();
}
}
Assert.isNotNull(bugReportID);
Assert.isNotNull(source);
Assert.isNotNull(contentType);
if (description == null) {
throw new CoreException(new Status(IStatus.WARNING, BugzillaCorePlugin.ID_PLUGIN,
Messages.BugzillaClient_description_required_when_submitting_attachments));
}
hostConfiguration = WebUtil.createHostConfiguration(httpClient, location, monitor);
authenticate(monitor);
GzipPostMethod postMethod = null;
try {
postMethod = new GzipPostMethod(WebUtil.getRequestPath(repositoryUrl
+ IBugzillaConstants.URL_POST_ATTACHMENT_UPLOAD), true);
// This option causes the client to first
// check
// with the server to see if it will in fact receive the post before
// actually sending the contents.
postMethod.getParams().setBooleanParameter(HttpMethodParams.USE_EXPECT_CONTINUE, true);
List<PartBase> parts = new ArrayList<PartBase>();
parts.add(new StringPart(IBugzillaConstants.POST_INPUT_ACTION, VALUE_ACTION_INSERT, getCharacterEncoding()));
AuthenticationCredentials credentials = location.getCredentials(AuthenticationType.REPOSITORY);
String username;
String password;
if (credentials != null) {
username = credentials.getUserName();
password = credentials.getPassword();
} else {
username = null;
password = null;
}
if (username != null && password != null) {
parts.add(new StringPart(IBugzillaConstants.POST_INPUT_BUGZILLA_LOGIN, username, getCharacterEncoding()));
parts.add(new StringPart(IBugzillaConstants.POST_INPUT_BUGZILLA_PASSWORD, password,
getCharacterEncoding()));
}
parts.add(new StringPart(IBugzillaConstants.POST_INPUT_BUGID, bugReportID, getCharacterEncoding()));
if (description != null) {
parts.add(new StringPart(IBugzillaConstants.POST_INPUT_DESCRIPTION, description, getCharacterEncoding()));
}
if (comment != null) {
parts.add(new StringPart(IBugzillaConstants.POST_INPUT_COMMENT, comment, getCharacterEncoding()));
}
parts.add(new FilePart(IBugzillaConstants.POST_INPUT_DATA, new TaskAttachmentPartSource(source, filename)));
if (isPatch) {
parts.add(new StringPart(ATTRIBUTE_ISPATCH, VALUE_ISPATCH));
} else {
parts.add(new StringPart(ATTRIBUTE_CONTENTTYPEMETHOD, VALUE_CONTENTTYPEMETHOD_MANUAL));
parts.add(new StringPart(ATTRIBUTE_CONTENTTYPEENTRY, contentType));
}
if (attachmentAttribute != null) {
Collection<TaskAttribute> attributes = attachmentAttribute.getAttributes().values();
Iterator<TaskAttribute> itr = attributes.iterator();
while (itr.hasNext()) {
TaskAttribute a = itr.next();
if (a.getId().startsWith(BugzillaAttribute.KIND_FLAG_TYPE) && repositoryConfiguration != null) {
List<BugzillaFlag> flags = repositoryConfiguration.getFlags();
TaskAttribute requestee = a.getAttribute("requestee"); //$NON-NLS-1$
a = a.getAttribute("state"); //$NON-NLS-1$
String value = a.getValue();
String id = ""; //$NON-NLS-1$
if (value.equals(" ")) { //$NON-NLS-1$
continue;
}
String flagname = a.getMetaData().getLabel();
BugzillaFlag theFlag = null;
for (BugzillaFlag bugzillaFlag : flags) {
if (flagname.equals(bugzillaFlag.getName())) {
theFlag = bugzillaFlag;
break;
}
}
if (theFlag != null) {
int flagTypeNumber = theFlag.getFlagId();
id = "flag_type-" + flagTypeNumber; //$NON-NLS-1$
value = a.getValue();
if (value.equals("?") && requestee != null) { //$NON-NLS-1$
parts.add(new StringPart("requestee_type-" + flagTypeNumber, //$NON-NLS-1$
requestee.getValue() != null ? requestee.getValue() : "")); //$NON-NLS-1$
}
}
parts.add(new StringPart(id, value != null ? value : "")); //$NON-NLS-1$
} else if (a.getId().startsWith(BugzillaAttribute.KIND_FLAG)) {
TaskAttribute flagnumber = a.getAttribute("number"); //$NON-NLS-1$
TaskAttribute requestee = a.getAttribute("requestee"); //$NON-NLS-1$
a = a.getAttribute("state"); //$NON-NLS-1$
String id = "flag-" + flagnumber.getValue(); //$NON-NLS-1$
String value = a.getValue();
if (value.equals(" ") || value.equals("")) { //$NON-NLS-1$ //$NON-NLS-2$
value = "X"; //$NON-NLS-1$
}
if (value.equals("?") && requestee != null) { //$NON-NLS-1$
parts.add(new StringPart("requestee-" + flagnumber.getValue(), //$NON-NLS-1$
requestee.getValue() != null ? requestee.getValue() : "")); //$NON-NLS-1$
}
parts.add(new StringPart(id, value != null ? value : "")); //$NON-NLS-1$
}
}
}
postMethod.setRequestEntity(new MultipartRequestEntity(parts.toArray(new Part[1]), postMethod.getParams()));
postMethod.setDoAuthentication(true);
int status = WebUtil.execute(httpClient, hostConfiguration, postMethod, monitor);
if (status == HttpStatus.SC_OK) {
InputStream input = getResponseStream(postMethod, monitor);
try {
parsePostResponse(bugReportID, input);
} finally {
input.close();
}
} else {
WebUtil.releaseConnection(postMethod, monitor);
throw new CoreException(new BugzillaStatus(IStatus.ERROR, BugzillaCorePlugin.ID_PLUGIN,
RepositoryStatus.ERROR_NETWORK, repositoryUrl.toString(), "Http error: " //$NON-NLS-1$
+ HttpStatus.getStatusText(status)));
// throw new IOException("Communication error occurred during
// upload. \n\n"
// + HttpStatus.getStatusText(status));
}
} finally {
if (postMethod != null) {
WebUtil.releaseConnection(postMethod, monitor);
}
}
}
/**
* calling method must release the connection on the returned PostMethod once finished.
*
* @throws CoreException
*/
private GzipPostMethod postFormData(String formUrl, NameValuePair[] formData, IProgressMonitor monitor)
throws IOException, CoreException {
GzipPostMethod postMethod = null;
monitor = Policy.monitorFor(monitor);
hostConfiguration = WebUtil.createHostConfiguration(httpClient, location, monitor);
authenticate(monitor);
postMethod = new GzipPostMethod(WebUtil.getRequestPath(repositoryUrl.toString() + formUrl), true);
postMethod.setRequestHeader(
"Content-Type", "application/x-www-form-urlencoded; charset=" + getCharacterEncoding()); //$NON-NLS-1$ //$NON-NLS-2$
httpClient.getHttpConnectionManager().getParams().setSoTimeout(WebUtil.getConnectionTimeout());
postMethod.setRequestBody(formData);
postMethod.setDoAuthentication(true);
int status = WebUtil.execute(httpClient, hostConfiguration, postMethod, monitor);
if (status == HttpStatus.SC_OK) {
return postMethod;
} else if (status == HttpStatus.SC_MOVED_TEMPORARILY) {
String redirectLocation;
Header locationHeader = postMethod.getResponseHeader("location"); //$NON-NLS-1$
if (locationHeader != null) {
redirectLocation = locationHeader.getValue();
WebUtil.releaseConnection(postMethod, monitor);
throw new RedirectException(redirectLocation);
}
}
WebUtil.releaseConnection(postMethod, monitor);
throw new CoreException(new BugzillaStatus(IStatus.ERROR, BugzillaCorePlugin.ID_PLUGIN,
RepositoryStatus.ERROR_IO, repositoryUrl.toString(), new IOException(
"Communication error occurred during upload. \n\n" + HttpStatus.getStatusText(status)))); //$NON-NLS-1$
}
public void postUpdateAttachment(TaskAttribute taskAttribute, String action, IProgressMonitor monitor)
throws IOException, CoreException {
List<NameValuePair> formData = new ArrayList<NameValuePair>(5);
formData.add(new NameValuePair("action", action)); //$NON-NLS-1$
formData.add(new NameValuePair("contenttypemethod", "manual")); //$NON-NLS-1$ //$NON-NLS-2$
formData.add(new NameValuePair("id", taskAttribute.getValue())); //$NON-NLS-1$
Collection<TaskAttribute> attributes = taskAttribute.getAttributes().values();
Iterator<TaskAttribute> itr = attributes.iterator();
while (itr.hasNext()) {
TaskAttribute attrib = itr.next();
String id = attrib.getId();
String value = attrib.getValue();
if (id.equals(TaskAttribute.ATTACHMENT_AUTHOR) || id.equals("date") || id.equals("size") //$NON-NLS-1$ //$NON-NLS-2$
|| id.equals(TaskAttribute.ATTACHMENT_URL)) {
continue;
}
if (id.equals("desc")) { //$NON-NLS-1$
id = "description"; //$NON-NLS-1$
}
if (id.equals("ctype")) { //$NON-NLS-1$
id = "contenttypeentry"; //$NON-NLS-1$
}
if (id.equals(TaskAttribute.ATTACHMENT_IS_DEPRECATED)) {
id = "isobsolete"; //$NON-NLS-1$
}
if (id.equals(TaskAttribute.ATTACHMENT_IS_PATCH)) {
id = "ispatch"; //$NON-NLS-1$
}
if (id.startsWith(BugzillaAttribute.KIND_FLAG_TYPE)) {
TaskAttribute requestee = attrib.getAttribute("requestee"); //$NON-NLS-1$
TaskAttribute state = attrib.getAttribute("state"); //$NON-NLS-1$
String requesteeName = "requestee_type-" + id.substring(26); //$NON-NLS-1$
String requesteeValue = requestee.getValue();
value = state.getValue();
if (value.equals(" ") || value.equals("")) { //$NON-NLS-1$ //$NON-NLS-2$
value = "X"; //$NON-NLS-1$
}
if (value.equals("?")) { //$NON-NLS-1$
formData.add(new NameValuePair(requesteeName, requesteeValue));
}
id = "flag_type-" + id.substring(26); //$NON-NLS-1$
} else if (id.startsWith(BugzillaAttribute.KIND_FLAG)) {
TaskAttribute requestee = attrib.getAttribute("requestee"); //$NON-NLS-1$
TaskAttribute state = attrib.getAttribute("state"); //$NON-NLS-1$
String requesteeName = "requestee-" + id.substring(21); //$NON-NLS-1$
String requesteeValue = requestee.getValue();
value = state.getValue();
if (value.equals(" ") || value.equals("")) { //$NON-NLS-1$//$NON-NLS-2$
value = "X"; //$NON-NLS-1$
}
if (value.equals("?")) { //$NON-NLS-1$
formData.add(new NameValuePair(requesteeName, requesteeValue));
}
id = "flag-" + id.substring(21); //$NON-NLS-1$
}
if (!value.equals("")) { //$NON-NLS-1$
formData.add(new NameValuePair(id, value));
}
}
GzipPostMethod method = null;
InputStream input = null;
try {
method = postFormData(PROCESS_ATTACHMENT_CGI, formData.toArray(new NameValuePair[formData.size()]), monitor);
if (method == null) {
throw new IOException(Messages.BugzillaClient_could_not_post_form_null_returned);
}
input = getResponseStream(method, monitor);
parsePostResponse(taskAttribute.getTaskData().getTaskId(), input);
// BufferedReader in = new BufferedReader(new InputStreamReader(input, method.getRequestCharSet()));
// if (in.markSupported()) {
// in.mark(1);
// }
// HtmlStreamTokenizer tokenizer = new HtmlStreamTokenizer(in, null);
//
// boolean isTitle = false;
// String title = ""; //$NON-NLS-1$
//
// for (Token token = tokenizer.nextToken(); token.getType() != Token.EOF; token = tokenizer.nextToken()) {
//
// if (token.getType() == Token.TAG && ((HtmlTag) (token.getValue())).getTagType() == Tag.TITLE
// && !((HtmlTag) (token.getValue())).isEndTag()) {
// isTitle = true;
// continue;
// }
//
// if (isTitle) {
// // get all of the data in the title tag
// if (token.getType() != Token.TAG) {
// title += ((StringBuffer) token.getValue()).toString().toLowerCase(Locale.ENGLISH) + " "; //$NON-NLS-1$
// continue;
// } else if (token.getType() == Token.TAG && ((HtmlTag) token.getValue()).getTagType() == Tag.TITLE
// && ((HtmlTag) token.getValue()).isEndTag()) {
//
// for (Iterator<String> iterator = bugzillaLanguageSettings.getResponseForCommand(
// BugzillaLanguageSettings.COMMAND_CHANGES_SUBMITTED).iterator(); iterator.hasNext()
// && !existingBugPosted;) {
// String value = iterator.next().toLowerCase(Locale.ENGLISH);
// existingBugPosted = existingBugPosted || title.indexOf(value) != -1;
// }
// break;
// }
// }
// }
//
// if (existingBugPosted != true) {
// try {
// if (in.markSupported()) {
// in.reset();
// }
// } catch (IOException e) {
// // ignore
// }
// parseHtmlError(in);
// }
//
// } catch (ParseException e) {
// loggedIn = false;
// throw new CoreException(new BugzillaStatus(IStatus.ERROR, BugzillaCorePlugin.ID_PLUGIN,
// RepositoryStatus.ERROR_INTERNAL, "Unable to parse response from " + repositoryUrl.toString() + ".")); //$NON-NLS-1$ //$NON-NLS-2$
} finally {
if (input != null) {
input.close();
}
if (method != null) {
WebUtil.releaseConnection(method, monitor);
}
}
}
public RepositoryResponse postTaskData(TaskData taskData, IProgressMonitor monitor) throws IOException,
CoreException {
try {
return postTaskDataInternal(taskData, monitor);
} catch (CoreException e) {
TaskAttribute qaContact = taskData.getRoot().getAttribute(BugzillaAttribute.QA_CONTACT.getKey());
if (qaContact != null) {
String qaContactValue = qaContact.getValue();
String message = e.getMessage();
if ("An unknown repository error has occurred: Bugzilla/Bug.pm line".equals(message) //$NON-NLS-1$
&& qaContactValue != null && !qaContactValue.equals("")) { //$NON-NLS-1$
if (e.getStatus() instanceof RepositoryStatus) {
RepositoryStatus repositoryStatus = (RepositoryStatus) e.getStatus();
RepositoryStatus status = RepositoryStatus.createHtmlStatus(
repositoryStatus.getRepositoryUrl(), IStatus.INFO, BugzillaCorePlugin.ID_PLUGIN,
RepositoryStatus.ERROR_REPOSITORY,
"Error may result when QAContact field not enabled.", //$NON-NLS-1$
repositoryStatus.getHtmlMessage());
throw new CoreException(status);
}
}
}
try {
if (e.getStatus().getCode() == RepositoryStatus.ERROR_REPOSITORY_LOGIN) {
return postTaskDataInternal(taskData, monitor);
} else if (e.getStatus().getCode() == IBugzillaConstants.REPOSITORY_STATUS_SUSPICIOUS_ACTION) {
taskData.getRoot().removeAttribute(BugzillaAttribute.TOKEN.getKey());
return postTaskDataInternal(taskData, monitor);
} else {
throw e;
}
} catch (CoreException e1) {
throw e1;
}
}
}
public RepositoryResponse postTaskDataInternal(TaskData taskData, IProgressMonitor monitor) throws IOException,
CoreException {
NameValuePair[] formData = null;
monitor = Policy.monitorFor(monitor);
BugzillaRepositoryResponse response;
authenticate(new SubProgressMonitor(monitor, 1));
if (repositoryConfiguration == null) {
getRepositoryConfiguration(new SubProgressMonitor(monitor, 1), null);
connector.addRepositoryConfiguration(repositoryConfiguration);
}
if (taskData == null) {
return null;
} else if (taskData.isNew()) {
formData = getPairsForNew(taskData);
} else {
formData = getPairsForExisting(taskData, new SubProgressMonitor(monitor, 1));
}
GzipPostMethod method = null;
InputStream input = null;
try {
if (taskData.isNew()) {
method = postFormData(POST_BUG_CGI, formData, monitor);
} else {
method = postFormData(PROCESS_BUG_CGI, formData, monitor);
}
if (method == null) {
throw new IOException("Could not post form, client returned null method."); //$NON-NLS-1$
}
input = getResponseStream(method, monitor);
response = parsePostResponse(taskData.getTaskId(), input);
return response;
} catch (CoreException e) {
throw e;
} finally {
if (input != null) {
input.close();
}
if (method != null) {
WebUtil.releaseConnection(method, monitor);
}
}
}
private NameValuePair[] getPairsForNew(TaskData taskData) {
Map<String, NameValuePair> fields = new HashMap<String, NameValuePair>();
BugzillaVersion bugzillaVersion = null;
if (repositoryConfiguration != null) {
bugzillaVersion = repositoryConfiguration.getInstallVersion();
} else {
bugzillaVersion = BugzillaVersion.MIN_VERSION;
}
// go through all of the attributes and add them to
// the bug post
Collection<TaskAttribute> attributes = new ArrayList<TaskAttribute>(taskData.getRoot().getAttributes().values());
Iterator<TaskAttribute> itr = attributes.iterator();
while (itr.hasNext()) {
TaskAttribute a = itr.next();
if (a != null && a.getId() != null && a.getId().compareTo("") != 0) { //$NON-NLS-1$
String value = null;
value = a.getValue();
if (value == null) {
continue;
}
String id = a.getId();
if (id.equals(BugzillaAttribute.BUG_STATUS.getKey())
&& bugzillaVersion.compareMajorMinorOnly(BugzillaVersion.BUGZILLA_4_0) >= 0) {
TaskAttribute attributeOperation = taskData.getRoot().getMappedAttribute(TaskAttribute.OPERATION);
value = attributeOperation.getValue().toUpperCase();
if (!BugzillaOperation.new_default.toString().toUpperCase().equals(value)) {
fields.put(id, new NameValuePair(id, value != null ? value : "")); //$NON-NLS-1$
} else {
continue;
}
}
if (id.equals(BugzillaAttribute.NEWCC.getKey())) {
TaskAttribute b = taskData.getRoot().createAttribute(BugzillaAttribute.CC.getKey());
b.getMetaData()
.defaults()
.setReadOnly(BugzillaAttribute.CC.isReadOnly())
.setKind(BugzillaAttribute.CC.getKind())
.setLabel(BugzillaAttribute.CC.toString())
.setType(BugzillaAttribute.CC.getType());
for (String val : a.getValues()) {
if (val != null) {
b.addValue(val);
}
}
a = b;
id = a.getId();
cleanIfShortLogin(a);
} else {
cleanQAContact(a);
}
if (a.getMetaData().getType() != null
&& a.getMetaData().getType().equals(TaskAttribute.TYPE_MULTI_SELECT)) {
List<String> values = a.getValues();
int i = 0;
for (String string : values) {
fields.put(id + i++, new NameValuePair(id, string != null ? string : "")); //$NON-NLS-1$
}
} else if (id != null && id.compareTo("") != 0) { //$NON-NLS-1$
fields.put(id, new NameValuePair(id, value != null ? value : "")); //$NON-NLS-1$
}
}
}
TaskAttribute descAttribute = taskData.getRoot().getMappedAttribute(TaskAttribute.DESCRIPTION);
if (descAttribute != null && !descAttribute.getValue().equals("")) { //$NON-NLS-1$
if (bugzillaVersion.compareMajorMinorOnly(BugzillaVersion.BUGZILLA_2_18) == 0) {
fields.put(KEY_COMMENT,
new NameValuePair(KEY_COMMENT, formatTextToLineWrap(descAttribute.getValue(), true)));
} else {
fields.put(KEY_COMMENT, new NameValuePair(KEY_COMMENT, descAttribute.getValue()));
}
}
return fields.values().toArray(new NameValuePair[fields.size()]);
}
private void cleanQAContact(TaskAttribute a) {
if (a.getId().equals(BugzillaAttribute.QA_CONTACT.getKey())) {
cleanIfShortLogin(a);
}
}
private void cleanIfShortLogin(TaskAttribute a) {
if ("true".equals(configParameters.get(IBugzillaConstants.REPOSITORY_SETTING_SHORT_LOGIN))) { //$NON-NLS-1$
if (a.getValue() != null && a.getValue().length() > 0) {
int atIndex = a.getValue().indexOf("@"); //$NON-NLS-1$
if (atIndex != -1) {
String newValue = a.getValue().substring(0, atIndex);
a.setValue(newValue);
}
}
}
}
private NameValuePair[] getPairsForExisting(TaskData model, IProgressMonitor monitor) throws CoreException {
boolean groupSecurityEnabled = false;
Map<String, NameValuePair> fields = new HashMap<String, NameValuePair>();
fields.put(KEY_FORM_NAME, new NameValuePair(KEY_FORM_NAME, VAL_PROCESS_BUG));
// go through all of the attributes and add them to the bug post
Collection<TaskAttribute> attributes = model.getRoot().getAttributes().values();
Iterator<TaskAttribute> itr = attributes.iterator();
boolean tokenFound = false;
boolean tokenRequired = false;
BugzillaVersion bugzillaVersion = null;
if (repositoryConfiguration != null) {
bugzillaVersion = repositoryConfiguration.getInstallVersion();
} else {
bugzillaVersion = BugzillaVersion.MIN_VERSION;
}
while (itr.hasNext()) {
TaskAttribute a = itr.next();
if (a == null) {
continue;
} else {
String id = a.getId();
if (id.equalsIgnoreCase(BugzillaAttribute.TOKEN.getKey())) {
tokenFound = true;
} else if (id.equals(BugzillaAttribute.QA_CONTACT.getKey())
|| id.equals(BugzillaAttribute.ASSIGNED_TO.getKey())) {
cleanIfShortLogin(a);
} else if (id.equals(BugzillaAttribute.REPORTER.getKey()) || id.equals(BugzillaAttribute.CC.getKey())
|| id.equals(BugzillaAttribute.REMOVECC.getKey())
|| id.equals(BugzillaAttribute.CREATION_TS.getKey())
|| id.equals(BugzillaAttribute.BUG_STATUS.getKey())
|| id.equals(BugzillaAttribute.VOTES.getKey())) {
continue;
} else if (id.equals(BugzillaAttribute.NEW_COMMENT.getKey())) {
if (bugzillaVersion.compareMajorMinorOnly(BugzillaVersion.BUGZILLA_2_18) == 0) {
a.setValue(formatTextToLineWrap(a.getValue(), true));
}
} else if (id.equals(BugzillaAttribute.GROUP.getKey()) && a.getValue().length() > 0) {
groupSecurityEnabled = true;
}
if (a.getMetaData().getType() != null
&& a.getMetaData().getType().equals(TaskAttribute.TYPE_MULTI_SELECT)) {
List<String> values = a.getValues();
int i = 0;
for (String string : values) {
fields.put(id + i++, new NameValuePair(id, string != null ? string : "")); //$NON-NLS-1$
}
} else if (id != null && id.compareTo("") != 0) { //$NON-NLS-1$
String value = a.getValue();
if (id.equals(BugzillaAttribute.DELTA_TS.getKey())) {
if (bugzillaVersion.compareTo(BugzillaVersion.BUGZILLA_3_4_7) < 0
|| (bugzillaVersion.compareTo(BugzillaVersion.BUGZILLA_3_5) >= 0)
&& bugzillaVersion.compareTo(BugzillaVersion.BUGZILLA_3_6) < 0) {
value = stripTimeZone(value);
}
}
if (id.startsWith(BugzillaAttribute.KIND_FLAG_TYPE) && repositoryConfiguration != null) {
List<BugzillaFlag> flags = repositoryConfiguration.getFlags();
TaskAttribute requestee = a.getAttribute("requestee"); //$NON-NLS-1$
a = a.getAttribute("state"); //$NON-NLS-1$
value = a.getValue();
if (value.equals(" ") || value.equals("")) { //$NON-NLS-1$ //$NON-NLS-2$
continue;
}
String flagname = a.getMetaData().getLabel();
BugzillaFlag theFlag = null;
for (BugzillaFlag bugzillaFlag : flags) {
if (flagname.equals(bugzillaFlag.getName()) && bugzillaFlag.getType().equals("bug")) { //$NON-NLS-1$
theFlag = bugzillaFlag;
break;
}
}
if (theFlag != null) {
int flagTypeNumber = theFlag.getFlagId();
id = "flag_type-" + flagTypeNumber; //$NON-NLS-1$
value = a.getValue();
if (value.equals("?") && requestee != null) { //$NON-NLS-1$
fields.put("requestee_type-" + flagTypeNumber, new NameValuePair("requestee_type-" //$NON-NLS-1$ //$NON-NLS-2$
+ flagTypeNumber, requestee.getValue() != null ? requestee.getValue() : "")); //$NON-NLS-1$
}
}
} else if (id.startsWith(BugzillaAttribute.KIND_FLAG)) {
TaskAttribute flagnumber = a.getAttribute("number"); //$NON-NLS-1$
TaskAttribute requestee = a.getAttribute("requestee"); //$NON-NLS-1$
a = a.getAttribute("state"); //$NON-NLS-1$
id = "flag-" + flagnumber.getValue(); //$NON-NLS-1$
value = a.getValue();
if (value.equals(" ") || value.equals("")) { //$NON-NLS-1$ //$NON-NLS-2$
value = "X"; //$NON-NLS-1$
}
if (value.equals("?") && requestee != null) { //$NON-NLS-1$
fields.put("requestee-" + flagnumber.getValue(), new NameValuePair("requestee-" //$NON-NLS-1$//$NON-NLS-2$
+ flagnumber.getValue(), requestee.getValue() != null ? requestee.getValue() : "")); //$NON-NLS-1$
}
} else if (id.startsWith(TaskAttribute.PREFIX_COMMENT)) {
TaskAttribute commentID = a.getAttribute(BugzillaAttribute.COMMENTID.getKey());
if (commentID != null) {
String valueID = commentID.getValue();
TaskAttribute definedIsPrivate = a.getAttribute(IBugzillaConstants.BUGZILLA_PREFIX_DEFINED_ISPRIVATE
+ valueID);
if (definedIsPrivate != null) {
fields.put(definedIsPrivate.getId(), new NameValuePair(definedIsPrivate.getId(),
definedIsPrivate.getValue() != null ? definedIsPrivate.getValue() : "")); //$NON-NLS-1$
}
TaskAttribute isPrivate = a.getAttribute(IBugzillaConstants.BUGZILLA_PREFIX_ISPRIVATE
+ valueID);
if (isPrivate != null) {
fields.put(isPrivate.getId(), new NameValuePair(isPrivate.getId(),
isPrivate.getValue() != null ? isPrivate.getValue() : "")); //$NON-NLS-1$
}
continue;
}
} else if (id.startsWith("task.common.")) { //$NON-NLS-1$
// Don't post any remaining non-bugzilla specific attributes
continue;
}
fields.put(id, new NameValuePair(id, value != null ? value : "")); //$NON-NLS-1$
}
}
}
// when posting the bug id is encoded in a hidden field named 'id'
TaskAttribute attributeBugId = model.getRoot().getAttribute(BugzillaAttribute.BUG_ID.getKey());
if (attributeBugId != null) {
fields.put(KEY_ID, new NameValuePair(KEY_ID, attributeBugId.getValue()));
}
// add the operation to the bug post
if (bugzillaVersion.compareTo(BugzillaVersion.BUGZILLA_3_2) < 0) {
TaskAttribute attributeOperation = model.getRoot().getMappedAttribute(TaskAttribute.OPERATION);
if (attributeOperation == null) {
fields.put(KEY_KNOB, new NameValuePair(KEY_KNOB, VAL_NONE));
} else {
TaskAttribute originalOperation = model.getRoot().getAttribute(
TaskAttribute.PREFIX_OPERATION + attributeOperation.getValue());
if (originalOperation == null) {
// Work around for bug#241012
fields.put(KEY_KNOB, new NameValuePair(KEY_KNOB, VAL_NONE));
} else {
String inputAttributeId = originalOperation.getMetaData().getValue(
TaskAttribute.META_ASSOCIATED_ATTRIBUTE_ID);
if (inputAttributeId == null || inputAttributeId.equals("")) { //$NON-NLS-1$
String sel = attributeOperation.getValue();
fields.put(KEY_KNOB, new NameValuePair(KEY_KNOB, sel));
} else {
fields.put(KEY_KNOB, new NameValuePair(KEY_KNOB, attributeOperation.getValue()));
TaskAttribute inputAttribute = attributeOperation.getTaskData()
.getRoot()
.getAttribute(inputAttributeId);
if (inputAttribute != null) {
if (inputAttribute.getOptions().size() > 0) {
String sel = inputAttribute.getValue();
String knob = inputAttribute.getId();
if (knob.equals(BugzillaOperation.resolve.getInputId())
|| knob.equals(BugzillaOperation.close_with_resolution.getInputId())) {
knob = BugzillaAttribute.RESOLUTION.getKey();
}
fields.put(knob, new NameValuePair(knob, inputAttribute.getOption(sel)));
} else {
String sel = inputAttribute.getValue();
String knob = attributeOperation.getValue();
if (knob.equals(BugzillaOperation.reassign.toString())) {
knob = BugzillaAttribute.ASSIGNED_TO.getKey();
}
fields.put(knob, new NameValuePair(knob, sel));
}
}
}
}
if (model.getRoot().getMappedAttribute(TaskAttribute.COMMENT_NEW) != null
&& model.getRoot().getMappedAttribute(TaskAttribute.COMMENT_NEW).getValue().length() > 0) {
fields.put(KEY_COMMENT,
new NameValuePair(KEY_COMMENT, model.getRoot()
.getMappedAttribute(TaskAttribute.COMMENT_NEW)
.getValue()));
} else if (attributeOperation != null
&& attributeOperation.getValue().equals(BugzillaOperation.duplicate.toString())) {
// fix for bug#198677
fields.put(KEY_COMMENT, new NameValuePair(KEY_COMMENT, "")); //$NON-NLS-1$
}
}
} else {
// A token is required for bugzilla 3.2.1 and newer
tokenRequired = bugzillaVersion.compareTo(BugzillaVersion.BUGZILLA_3_2) > 0;
String fieldName = BugzillaAttribute.BUG_STATUS.getKey();
TaskAttribute attributeStatus = model.getRoot().getMappedAttribute(TaskAttribute.STATUS);
TaskAttribute attributeOperation = model.getRoot().getMappedAttribute(TaskAttribute.OPERATION);
if (attributeOperation == null) {
fields.put(fieldName, new NameValuePair(fieldName, attributeStatus.getValue()));
} else {
TaskAttribute originalOperation = model.getRoot().getAttribute(
TaskAttribute.PREFIX_OPERATION + attributeOperation.getValue());
if (originalOperation == null) {
// Work around for bug#241012
fields.put(fieldName, new NameValuePair(fieldName, attributeStatus.getValue()));
} else {
String inputAttributeId = originalOperation.getMetaData().getValue(
TaskAttribute.META_ASSOCIATED_ATTRIBUTE_ID);
String selOp = attributeOperation.getValue().toUpperCase();
if (selOp.equals("NONE")) { //$NON-NLS-1$
selOp = attributeStatus.getValue();
}
if (selOp.equals("ACCEPT")) { //$NON-NLS-1$
selOp = "ASSIGNED"; //$NON-NLS-1$
}
if (selOp.equals("RESOLVE")) { //$NON-NLS-1$
selOp = "RESOLVED"; //$NON-NLS-1$
}
if (selOp.equals("VERIFY")) { //$NON-NLS-1$
selOp = "VERIFIED"; //$NON-NLS-1$
}
if (selOp.equals("CLOSE")) { //$NON-NLS-1$
selOp = "CLOSED"; //$NON-NLS-1$
}
if (selOp.equals("REOPEN")) { //$NON-NLS-1$
selOp = "REOPENED"; //$NON-NLS-1$
}
if (selOp.equals("MARKNEW")) { //$NON-NLS-1$
selOp = "NEW"; //$NON-NLS-1$
}
if (selOp.equals("DUPLICATE")) { //$NON-NLS-1$
if (repositoryConfiguration != null) {
selOp = repositoryConfiguration.getDuplicateStatus();
} else {
selOp = "RESOLVED"; //$NON-NLS-1$
}
String knob = BugzillaAttribute.RESOLUTION.getKey();
fields.put(knob, new NameValuePair(knob, "DUPLICATE")); //$NON-NLS-1$
}
fields.put(fieldName, new NameValuePair(fieldName, selOp));
if (inputAttributeId != null && !inputAttributeId.equals("")) { //$NON-NLS-1$
TaskAttribute inputAttribute = attributeOperation.getTaskData()
.getRoot()
.getAttribute(inputAttributeId);
if (inputAttribute != null) {
if (inputAttribute.getOptions().size() > 0) {
String sel = inputAttribute.getValue();
String knob = inputAttribute.getId();
if (knob.equals(BugzillaOperation.resolve.getInputId())) {
knob = BugzillaAttribute.RESOLUTION.getKey();
}
fields.put(knob, new NameValuePair(knob, inputAttribute.getOption(sel)));
} else {
String sel = inputAttribute.getValue();
String knob = attributeOperation.getValue();
if (knob.equals(BugzillaOperation.duplicate.toString())) {
knob = inputAttributeId;
}
if (knob.equals(BugzillaOperation.reassign.toString())) {
knob = BugzillaAttribute.ASSIGNED_TO.getKey();
}
fields.put(knob, new NameValuePair(knob, sel));
}
}
}
}
}
if (model.getRoot().getMappedAttribute(TaskAttribute.COMMENT_NEW) != null
&& model.getRoot().getMappedAttribute(TaskAttribute.COMMENT_NEW).getValue().length() > 0) {
fields.put(KEY_COMMENT,
new NameValuePair(KEY_COMMENT, model.getRoot()
.getMappedAttribute(TaskAttribute.COMMENT_NEW)
.getValue()));
}
}
if (model.getRoot().getMappedAttribute(BugzillaAttribute.SHORT_DESC.getKey()) != null) {
fields.put(
KEY_SHORT_DESC,
new NameValuePair(KEY_SHORT_DESC, model.getRoot()
.getMappedAttribute(BugzillaAttribute.SHORT_DESC.getKey())
.getValue()));
}
TaskAttribute attributeRemoveCC = model.getRoot().getMappedAttribute(BugzillaAttribute.REMOVECC.getKey());
if (attributeRemoveCC != null) {
List<String> removeCC = attributeRemoveCC.getValues();
if (removeCC != null && removeCC.size() > 0) {
String[] s = new String[removeCC.size()];
fields.put(KEY_CC, new NameValuePair(KEY_CC, toCommaSeparatedList(removeCC.toArray(s))));
fields.put(BugzillaAttribute.REMOVECC.getKey(), new NameValuePair(BugzillaAttribute.REMOVECC.getKey(),
VAL_TRUE));
}
}
// check for security token (required for successful submit on Bugzilla 3.2.1 and greater but not in xml until Bugzilla 3.2.3 bug#263318)
if (groupSecurityEnabled || (!tokenFound && tokenRequired)) {
// get security and token if exists from html and include in post
HtmlInformation htmlInfo = getHtmlOnlyInformation(model, monitor);
if (groupSecurityEnabled) {
for (String key : htmlInfo.getGroups().keySet()) {
fields.put(key, new NameValuePair(key, htmlInfo.getGroups().get(key)));
}
}
if (htmlInfo.getToken() != null && htmlInfo.getToken().length() > 0 && tokenRequired) {
NameValuePair tokenPair = fields.get(BugzillaAttribute.TOKEN.getKey());
if (tokenPair != null) {
tokenPair.setValue(htmlInfo.getToken());
} else {
fields.put(BugzillaAttribute.TOKEN.getKey(), new NameValuePair(BugzillaAttribute.TOKEN.getKey(),
htmlInfo.getToken()));
}
}
}
return fields.values().toArray(new NameValuePair[fields.size()]);
}
private HtmlInformation getHtmlOnlyInformation(TaskData taskData, IProgressMonitor monitor) throws CoreException {
HtmlInformation htmlInfo = new HtmlInformation();
authenticate(new SubProgressMonitor(monitor, 1));
hostConfiguration = WebUtil.createHostConfiguration(httpClient, location, monitor);
String bugUrl = taskData.getRepositoryUrl() + IBugzillaConstants.URL_GET_SHOW_BUG + taskData.getTaskId();
GzipGetMethod getMethod = new GzipGetMethod(WebUtil.getRequestPath(bugUrl), false);
getMethod.setRequestHeader("Content-Type", "text/xml; charset=" + getCharacterEncoding()); //$NON-NLS-1$ //$NON-NLS-2$
httpClient.getParams().setParameter("http.protocol.single-cookie-header", true); //$NON-NLS-1$
getMethod.setDoAuthentication(true);
int code;
InputStream inStream = null;
try {
code = WebUtil.execute(httpClient, hostConfiguration, getMethod, monitor);
if (code == HttpURLConnection.HTTP_OK) {
inStream = getResponseStream(getMethod, monitor);
HtmlStreamTokenizer tokenizer = new HtmlStreamTokenizer(new BufferedReader(new InputStreamReader(
inStream, getCharacterEncoding())), null);
for (Token token = tokenizer.nextToken(); token.getType() != Token.EOF; token = tokenizer.nextToken()) {
if (token.getType() == Token.TAG && ((HtmlTag) (token.getValue())).getTagType() == Tag.INPUT
&& !((HtmlTag) (token.getValue())).isEndTag()) {
HtmlTag tag = (HtmlTag) token.getValue();
// String name = tag.getAttribute("name");
String id = tag.getAttribute("id"); //$NON-NLS-1$
String checkedValue = tag.getAttribute("checked"); //$NON-NLS-1$
String type = tag.getAttribute("type"); //$NON-NLS-1$
String name = tag.getAttribute("name"); //$NON-NLS-1$
String value = tag.getAttribute("value"); //$NON-NLS-1$
if (type != null && type.equalsIgnoreCase("checkbox") && id != null && id.startsWith("bit-")) { //$NON-NLS-1$ //$NON-NLS-2$
htmlInfo.getGroups().put(id, checkedValue);
} else if (name != null && name.equalsIgnoreCase(BugzillaAttribute.TOKEN.getKey())
&& value != null && value.length() > 0) {
htmlInfo.setToken(value);
}
}
}
}
} catch (Exception e) {
throw new CoreException(new Status(IStatus.ERROR, BugzillaCorePlugin.ID_PLUGIN,
"Unable to retrieve group security information", e)); //$NON-NLS-1$
} finally {
if (inStream != null) {
try {
inStream.close();
} catch (IOException e) {
//ignore
}
}
WebUtil.releaseConnection(getMethod, monitor);
}
return htmlInfo;
}
public static String stripTimeZone(String longTime) {
String result = longTime;
if (longTime != null) {
String[] values = longTime.split(" "); //$NON-NLS-1$
if (values != null && values.length > 2) {
result = values[0] + " " + values[1]; //$NON-NLS-1$
}
}
return result;
}
private static String toCommaSeparatedList(String[] strings) {
StringBuffer buffer = new StringBuffer();
for (int i = 0; i < strings.length; i++) {
buffer.append(strings[i]);
if (i != strings.length - 1) {
buffer.append(","); //$NON-NLS-1$
}
}
return buffer.toString();
}
/**
* Utility method for determining what potential error has occurred from a bugzilla html reponse page
*/
private BugzillaRepositoryResponse parseHtmlError(InputStream inputStream) throws IOException, CoreException {
BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, getCharacterEncoding()));
return parseRepositoryResponse(null, in);
}
private BugzillaRepositoryResponse parsePostResponse(String taskId, InputStream inputStream) throws IOException,
CoreException {
BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, getCharacterEncoding()));
return parseRepositoryResponse(taskId, in);
}
private BugzillaRepositoryResponse parseRepositoryResponse(String taskId, BufferedReader in) throws IOException,
CoreException {
HtmlStreamTokenizer tokenizer = new HtmlStreamTokenizer(in, null);
BugzillaRepositoryResponse response;
boolean isTitle = false;
String title = ""; //$NON-NLS-1$
String body = ""; //$NON-NLS-1$
String errorMessage = null;
try {
for (Token token = tokenizer.nextToken(); token.getType() != Token.EOF; token = tokenizer.nextToken()) {
body += token.toString();
if (token.getType() == Token.TAG && ((HtmlTag) (token.getValue())).getTagType() == Tag.TITLE
&& !((HtmlTag) (token.getValue())).isEndTag()) {
isTitle = true;
continue;
}
if (isTitle) {
// get all of the data in the title tag
if (token.getType() != Token.TAG) {
title += ((StringBuffer) token.getValue()).toString().toLowerCase(Locale.ENGLISH) + " "; //$NON-NLS-1$
continue;
} else if (token.getType() == Token.TAG && ((HtmlTag) token.getValue()).getTagType() == Tag.TITLE
&& ((HtmlTag) token.getValue()).isEndTag()) {
boolean found = false;
// Results for posting to Existing bugs
for (String string : bugzillaLanguageSettings.getResponseForCommand(BugzillaLanguageSettings.COMMAND_CHANGES_SUBMITTED)) {
String value = string.toLowerCase(Locale.ENGLISH);
found = title.indexOf(value) != -1;
if (found) {
response = new BugzillaRepositoryResponse(ResponseKind.TASK_UPDATED, taskId);
parseResultOK(tokenizer, response);
return response;
}
}
for (String string : bugzillaLanguageSettings.getResponseForCommand(BugzillaLanguageSettings.COMMAND_PROCESSED)) {
String value = string.toLowerCase(Locale.ENGLISH);
found = title.indexOf(value) != -1;
if (found) {
response = new BugzillaRepositoryResponse(ResponseKind.TASK_UPDATED, taskId);
parseResultOK(tokenizer, response);
return response;
}
}
// Results for posting NEW bugs
for (String string : bugzillaLanguageSettings.getResponseForCommand(BugzillaLanguageSettings.COMMAND_SUBMITTED)) {
String value = string.toLowerCase(Locale.ENGLISH);
found = title.indexOf(value) != -1;
if (found) {
int stopIndex = title.indexOf(value);
if (stopIndex > -1) {
for (String string2 : bugzillaLanguageSettings.getResponseForCommand(BugzillaLanguageSettings.COMMAND_BUG)) {
value = string2.toLowerCase(Locale.ENGLISH);
int startIndex = title.indexOf(value);
if (startIndex > -1) {
startIndex = startIndex + value.length();
String result = (title.substring(startIndex, stopIndex)).trim();
response = new BugzillaRepositoryResponse(ResponseKind.TASK_CREATED, result);
parseResultOK(tokenizer, response);
return response;
}
}
}
StatusHandler.log(new BugzillaStatus(IStatus.INFO, BugzillaCorePlugin.ID_PLUGIN,
RepositoryStatus.ERROR_INTERNAL,
"Unable to retrieve new task id from: " + title)); //$NON-NLS-1$
throw new CoreException(new BugzillaStatus(IStatus.ERROR, BugzillaCorePlugin.ID_PLUGIN,
RepositoryStatus.ERROR_INTERNAL,
Messages.BugzillaClient_Unable_to_retrieve_new_task));
}
}
// Error results
for (String string : bugzillaLanguageSettings.getResponseForCommand(BugzillaLanguageSettings.COMMAND_ERROR_LOGIN)) {
String value = string.toLowerCase(Locale.ENGLISH);
found = title.indexOf(value) != -1;
if (found) {
loggedIn = false;
if (hasAuthenticationCredentials()) {
throw new CoreException(new BugzillaStatus(IStatus.ERROR,
BugzillaCorePlugin.ID_PLUGIN, RepositoryStatus.ERROR_REPOSITORY_LOGIN,
repositoryUrl.toString(), title));
} else {
throw new CoreException(new BugzillaStatus(IStatus.ERROR,
BugzillaCorePlugin.ID_PLUGIN, RepositoryStatus.ERROR_REPOSITORY_LOGIN,
repositoryUrl.toString(),
Messages.BugzillaClient_anonymous_user_not_allowed));
}
}
}
for (String string : bugzillaLanguageSettings.getResponseForCommand(BugzillaLanguageSettings.COMMAND_ERROR_COLLISION)) {
String value = string.toLowerCase(Locale.ENGLISH);
found = title.indexOf(value) != -1;
if (found) {
throw new CoreException(new BugzillaStatus(IStatus.ERROR, BugzillaCorePlugin.ID_PLUGIN,
RepositoryStatus.REPOSITORY_COLLISION, repositoryUrl.toString()));
}
}
for (String string : bugzillaLanguageSettings.getResponseForCommand(BugzillaLanguageSettings.COMMAND_ERROR_COMMENT_REQUIRED)) {
String value = string.toLowerCase(Locale.ENGLISH);
found = title.indexOf(value) != -1;
if (found) {
throw new CoreException(new BugzillaStatus(IStatus.INFO, BugzillaCorePlugin.ID_PLUGIN,
RepositoryStatus.REPOSITORY_COMMENT_REQUIRED));
}
}
for (String string : bugzillaLanguageSettings.getResponseForCommand(BugzillaLanguageSettings.COMMAND_SUSPICIOUS_ACTION)) {
String value = string.toLowerCase(Locale.ENGLISH);
found = title.indexOf(value) != -1;
if (found) {
for (Token tokenError = tokenizer.nextToken(); tokenError.getType() != Token.EOF; tokenError = tokenizer.nextToken()) {
body += tokenError.toString();
if (tokenError.getType() == Token.COMMENT) {
if (tokenError.getValue().toString().startsWith("reason=")) { //$NON-NLS-1$
String reason = tokenError.getValue().toString().substring(7);
throw new CoreException(new BugzillaStatus(IStatus.ERROR,
BugzillaCorePlugin.ID_PLUGIN,
IBugzillaConstants.REPOSITORY_STATUS_SUSPICIOUS_ACTION,
repositoryUrl.toString(), "Reason = " + reason)); //$NON-NLS-1$
}
}
}
throw new CoreException(new BugzillaStatus(IStatus.ERROR, BugzillaCorePlugin.ID_PLUGIN,
IBugzillaConstants.REPOSITORY_STATUS_SUSPICIOUS_ACTION,
repositoryUrl.toString(), "unknown reason because Bugzilla < 4.0 was used")); //$NON-NLS-1$
}
}
for (String string : bugzillaLanguageSettings.getResponseForCommand(BugzillaLanguageSettings.COMMAND_ERROR_LOGGED_OUT)) {
String value = string.toLowerCase(Locale.ENGLISH);
found = title.indexOf(value) != -1;
if (found) {
loggedIn = false;
throw new CoreException(new BugzillaStatus(IStatus.INFO, BugzillaCorePlugin.ID_PLUGIN,
RepositoryStatus.REPOSITORY_LOGGED_OUT,
"You have been logged out. Please retry operation.")); //$NON-NLS-1$
}
}
for (Iterator<String> iterator = bugzillaLanguageSettings.getResponseForCommand(
BugzillaLanguageSettings.COMMAND_ERROR_CONFIRM_MATCH).iterator(); iterator.hasNext()
&& !found;) {
String value = iterator.next().toLowerCase(Locale.ENGLISH);
found = found || title.indexOf(value) != -1;
}
if (found) {
BugzillaStatus status = new BugzillaStatus(IStatus.ERROR, BugzillaCorePlugin.ID_PLUGIN,
BugzillaStatus.ERROR_CONFIRM_MATCH, repositoryUrl.toString(), "Confirm Match", body); //$NON-NLS-1$
parseResultConfirmMatch(tokenizer, status);
}
found = false;
for (Iterator<String> iterator = bugzillaLanguageSettings.getResponseForCommand(
BugzillaLanguageSettings.COMMAND_ERROR_MATCH_FAILED).iterator(); iterator.hasNext()
&& !found;) {
String value = iterator.next().toLowerCase(Locale.ENGLISH);
found = found || title.indexOf(value) != -1;
}
if (found) {
BugzillaStatus status = new BugzillaStatus(IStatus.ERROR, BugzillaCorePlugin.ID_PLUGIN,
BugzillaStatus.ERROR_MATCH_FAILED, repositoryUrl.toString(), "Match Failed", body); //$NON-NLS-1$
parseResultMatchFailed(tokenizer, status);
}
isTitle = false;
}
} else {
if (isErrorMessageToken(token)) {
errorMessage = computeErrorMessage(tokenizer, token);
break;
}
}
}
if (hasAuthenticationCredentials() && !loggedIn) {
// None of the usual errors occurred. Log what cookies were received to aid authentication debugging
StringBuilder builder = new StringBuilder("Cookies: "); //$NON-NLS-1$
for (Cookie cookie : httpClient.getState().getCookies()) {
builder.append(cookie.getName() + " = " + cookie.getValue() + " "); //$NON-NLS-1$ //$NON-NLS-2$
}
StatusHandler.log(new Status(IStatus.WARNING, BugzillaCorePlugin.ID_PLUGIN, UNKNOWN_REPOSITORY_ERROR
+ body));
StatusHandler.log(new Status(IStatus.WARNING, BugzillaCorePlugin.ID_PLUGIN, builder.toString()));
}
String result = title.trim();
if (errorMessage != null) {
if (result.length() > 0) {
result = result + ": " + errorMessage; //$NON-NLS-1$
} else {
result = errorMessage;
}
throw new CoreException(RepositoryStatus.createHtmlStatus(repositoryUrl.toString(), IStatus.ERROR,
BugzillaCorePlugin.ID_PLUGIN, RepositoryStatus.ERROR_REPOSITORY, result, body));
}
if (result.length() == 0) {
if (body.contains("Bugzilla/Bug.pm line")) { //$NON-NLS-1$
result = "Bugzilla/Bug.pm line"; //$NON-NLS-1$
}
}
RepositoryStatus status = RepositoryStatus.createHtmlStatus(repositoryUrl.toString(), IStatus.INFO,
BugzillaCorePlugin.ID_PLUGIN, RepositoryStatus.ERROR_REPOSITORY, UNKNOWN_REPOSITORY_ERROR + result,
body);
throw new CoreException(status);
} catch (ParseException e) {
loggedIn = false;
throw new CoreException(new BugzillaStatus(IStatus.ERROR, BugzillaCorePlugin.ID_PLUGIN,
RepositoryStatus.ERROR_INTERNAL, "Unable to parse response from " + repositoryUrl.toString() + ".")); //$NON-NLS-1$ //$NON-NLS-2$
} finally {
in.close();
}
}
public TaskHistory getHistory(String taskId, IProgressMonitor monitor) throws IOException, CoreException {
hostConfiguration = WebUtil.createHostConfiguration(httpClient, location, monitor);
authenticate(monitor);
GzipGetMethod method = null;
try {
String url = repositoryUrl + IBugzillaConstants.SHOW_ACTIVITY + taskId;
method = getConnectGzip(url, monitor, null);
if (method != null) {
InputStream in = getResponseStream(method, monitor);
try {
BugzillaTaskHistoryParser parser = new BugzillaTaskHistoryParser(in, getCharacterEncoding());
try {
return parser.retrieveHistory(bugzillaLanguageSettings);
} catch (LoginException e) {
loggedIn = false;
throw new CoreException(new BugzillaStatus(IStatus.ERROR, BugzillaCorePlugin.ID_PLUGIN,
RepositoryStatus.ERROR_REPOSITORY_LOGIN, repositoryUrl.toString(),
IBugzillaConstants.INVALID_CREDENTIALS));
} catch (ParseException e) {
loggedIn = false;
throw new CoreException(new BugzillaStatus(IStatus.ERROR, BugzillaCorePlugin.ID_PLUGIN,
RepositoryStatus.ERROR_INTERNAL, "Unable to parse response from " //$NON-NLS-1$
+ repositoryUrl.toString() + ".")); //$NON-NLS-1$
}
} finally {
in.close();
}
}
} finally {
if (method != null) {
WebUtil.releaseConnection(method, monitor);
}
}
return null;
}
public void getTaskData(Set<String> taskIds, final TaskDataCollector collector, final TaskAttributeMapper mapper,
final IProgressMonitor monitor) throws IOException, CoreException {
if (repositoryConfiguration == null) {
getRepositoryConfiguration(new SubProgressMonitor(monitor, 1), null);
connector.addRepositoryConfiguration(repositoryConfiguration);
}
GzipPostMethod method = null;
HashMap<String, TaskData> taskDataMap = new HashMap<String, TaskData>();
// make a copy to modify set
taskIds = new HashSet<String>(taskIds);
int authenticationAttempt = 0;
while (taskIds.size() > 0) {
try {
Set<String> idsToRetrieve = new HashSet<String>();
Iterator<String> itr = taskIds.iterator();
for (int x = 0; itr.hasNext() && x < MAX_RETRIEVED_PER_QUERY; x++) {
String taskId = itr.next();
String taskIdOrg = taskId;
// remove leading zeros
boolean changed = false;
while (taskId.startsWith("0")) { //$NON-NLS-1$
taskId = taskId.substring(1);
changed = true;
}
idsToRetrieve.add(taskId);
if (changed) {
taskIds.remove(taskIdOrg);
taskIds.add(taskId);
}
}
NameValuePair[] formData = new NameValuePair[idsToRetrieve.size() + 2];
if (idsToRetrieve.size() == 0) {
return;
}
itr = idsToRetrieve.iterator();
int x = 0;
for (; itr.hasNext(); x++) {
String taskId = itr.next();
formData[x] = new NameValuePair("id", taskId); //$NON-NLS-1$
TaskData taskData = new TaskData(mapper, getConnectorKind(), repositoryUrl.toString(), taskId);
setupExistingBugAttributes(repositoryUrl.toString(), taskData);
taskDataMap.put(taskId, taskData);
}
formData[x++] = new NameValuePair("ctype", "xml"); //$NON-NLS-1$ //$NON-NLS-2$
formData[x] = new NameValuePair("excludefield", "attachmentdata"); //$NON-NLS-1$ //$NON-NLS-2$
method = postFormData(IBugzillaConstants.URL_POST_SHOW_BUG, formData, monitor);
if (method == null) {
throw new IOException("Could not post form, client returned null method."); //$NON-NLS-1$
}
boolean parseable = false;
if (method.getResponseHeader("Content-Type") != null) { //$NON-NLS-1$
Header responseTypeHeader = method.getResponseHeader("Content-Type"); //$NON-NLS-1$
for (String type : VALID_CONFIG_CONTENT_TYPES) {
if (responseTypeHeader.getValue().toLowerCase(Locale.ENGLISH).contains(type)) {
InputStream input = getResponseStream(method, monitor);
try {
MultiBugReportFactory factory = new MultiBugReportFactory(input,
getCharacterEncoding(), connector);
List<BugzillaCustomField> customFields = new ArrayList<BugzillaCustomField>();
if (repositoryConfiguration != null) {
customFields = repositoryConfiguration.getCustomFields();
}
factory.populateReport(taskDataMap, collector, mapper, customFields);
taskIds.removeAll(idsToRetrieve);
taskDataMap.clear();
parseable = true;
break;
} finally {
input.close();
}
}
}
}
if (!parseable) {
// because html is not a valid config content type it is save to get the response here
parseHtmlError(getResponseStream(method, monitor));
break;
}
} catch (CoreException c) {
if (c.getStatus().getCode() == RepositoryStatus.ERROR_REPOSITORY_LOGIN && authenticationAttempt < 1) {
loggedIn = false;
authenticationAttempt++;
//StatusHandler.log(c.getStatus());
} else {
throw c;
}
} finally {
if (method != null) {
WebUtil.releaseConnection(method, monitor);
}
}
}
}
protected String getConnectorKind() {
return BugzillaCorePlugin.CONNECTOR_KIND;
}
public String getConfigurationTimestamp(IProgressMonitor monitor) throws CoreException {
if (!lastModifiedSupported) {
return null;
}
String lastModified = null;
HeadMethod method = null;
try {
method = connectHead(repositoryUrl + IBugzillaConstants.URL_GET_CONFIG_RDF, monitor);
Header lastModifiedHeader = method.getResponseHeader("Last-Modified"); //$NON-NLS-1$
if (lastModifiedHeader != null && lastModifiedHeader.getValue() != null
&& lastModifiedHeader.getValue().length() > 0) {
lastModified = lastModifiedHeader.getValue();
} else {
lastModifiedSupported = false;
}
} catch (Exception e) {
lastModifiedSupported = false;
throw new CoreException(new Status(IStatus.ERROR, BugzillaCorePlugin.ID_PLUGIN,
"Error retrieving configuration timestamp", e)); //$NON-NLS-1$
} finally {
if (method != null) {
WebUtil.releaseConnection(method, monitor);
}
}
return lastModified;
}
private HeadMethod connectHead(String requestURL, IProgressMonitor monitor) throws IOException, CoreException {
hostConfiguration = WebUtil.createHostConfiguration(httpClient, location, monitor);
for (int attempt = 0; attempt < 2; attempt++) {
// force authentication
authenticate(monitor);
HeadMethod headMethod = new HeadMethod(WebUtil.getRequestPath(requestURL));
if (requestURL.contains(QUERY_DELIMITER)) {
headMethod.setQueryString(requestURL.substring(requestURL.indexOf(QUERY_DELIMITER)));
}
headMethod.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=" //$NON-NLS-1$ //$NON-NLS-2$
+ getCharacterEncoding());
// WARNING!! Setting browser compatability breaks Bugzilla
// authentication
// getMethod.getParams().setCookiePolicy(CookiePolicy.BROWSER_COMPATIBILITY);
// headMethod.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, new BugzillaRetryHandler());
headMethod.setDoAuthentication(true);
int code;
try {
code = WebUtil.execute(httpClient, hostConfiguration, headMethod, monitor);
} catch (IOException e) {
// ignore the response
WebUtil.releaseConnection(headMethod, monitor);
throw new CoreException(new BugzillaStatus(IStatus.ERROR, BugzillaCorePlugin.ID_PLUGIN,
RepositoryStatus.ERROR_IO, repositoryUrl.toString(), e));
}
if (code == HttpURLConnection.HTTP_OK) {
return headMethod;
} else if (code == HttpURLConnection.HTTP_UNAUTHORIZED || code == HttpURLConnection.HTTP_FORBIDDEN) {
// ignore the response
WebUtil.releaseConnection(headMethod, monitor);
loggedIn = false;
authenticate(monitor);
} else if (code == HttpURLConnection.HTTP_PROXY_AUTH) {
loggedIn = false;
// ignore the response
WebUtil.releaseConnection(headMethod, monitor);
throw new CoreException(new BugzillaStatus(IStatus.ERROR, BugzillaCorePlugin.ID_PLUGIN,
RepositoryStatus.ERROR_REPOSITORY_LOGIN, repositoryUrl.toString(),
"Proxy authentication required")); //$NON-NLS-1$
} else {
// ignore the response
WebUtil.releaseConnection(headMethod, monitor);
throw new CoreException(new BugzillaStatus(IStatus.ERROR, BugzillaCorePlugin.ID_PLUGIN,
RepositoryStatus.ERROR_NETWORK, "Http error: " + HttpStatus.getStatusText(code))); //$NON-NLS-1$
// throw new IOException("HttpClient connection error response
// code: " + code);
}
}
throw new CoreException(new BugzillaStatus(IStatus.ERROR, BugzillaCorePlugin.ID_PLUGIN,
RepositoryStatus.ERROR_INTERNAL, "All connection attempts to " + repositoryUrl.toString() //$NON-NLS-1$
+ " failed. Please verify connection and authentication information.")); //$NON-NLS-1$
}
public void setRepositoryConfiguration(RepositoryConfiguration repositoryConfiguration) {
this.repositoryConfiguration = repositoryConfiguration;
}
public RepositoryConfiguration getRepositoryConfiguration() {
return repositoryConfiguration;
}
/**
* Break text up into lines so that it is displayed properly in bugzilla
*/
public static String formatTextToLineWrap(String origText, boolean hardWrap) {
if (!hardWrap) {
return origText;
} else {
String newText = ""; //$NON-NLS-1$
while (!origText.equals("")) { //$NON-NLS-1$
int newLine = origText.indexOf('\n');
if (newLine == -1 || newLine > WRAP_LENGTH) {
if (origText.length() > WRAP_LENGTH) {
int spaceIndex = origText.lastIndexOf(" ", WRAP_LENGTH); //$NON-NLS-1$
if (spaceIndex == -1) {
spaceIndex = origText.indexOf(" ", WRAP_LENGTH); //$NON-NLS-1$
if (spaceIndex == -1) {
spaceIndex = newLine;
}
}
newText = newText + origText.substring(0, spaceIndex) + "\n"; //$NON-NLS-1$
if (origText.charAt(spaceIndex) == ' ' || origText.charAt(spaceIndex) == '\n') {
origText = origText.substring(spaceIndex + 1, origText.length());
} else {
origText = origText.substring(spaceIndex, origText.length());
}
} else {
newText = newText + origText;
origText = ""; //$NON-NLS-1$
}
} else {
newText = newText + origText.substring(0, newLine + 1);
origText = origText.substring(newLine + 1, origText.length());
}
}
return newText;
}
}
public static boolean isValidUrl(String url) {
if (url.startsWith("https://") || url.startsWith("http://")) { //$NON-NLS-1$//$NON-NLS-2$
try {
new URI(url, true, "UTF-8"); //$NON-NLS-1$
return true;
} catch (Exception e) {
return false;
}
}
return false;
}
private class HtmlInformation {
private final Map<String, String> groups;
private String token;
public HtmlInformation() {
groups = new HashMap<String, String>();
}
public Map<String, String> getGroups() {
return groups;
}
public void setToken(String token) {
this.token = token;
}
public String getToken() {
return token;
}
}
private void parseResultOK(HtmlStreamTokenizer tokenizer, BugzillaRepositoryResponse response) throws IOException,
CoreException {
String codeString = ""; //$NON-NLS-1$
boolean inBugzillaBody = false;
int dlLevel = 0;
boolean isDT = false;
boolean isCODE = false;
String dt1 = ""; //$NON-NLS-1$
String dt2 = ""; //$NON-NLS-1$
try {
for (Token token = tokenizer.nextToken(); token.getType() != Token.EOF; token = tokenizer.nextToken()) {
if (token.getType() == Token.TAG && ((HtmlTag) (token.getValue())).getTagType() == Tag.DIV) {
String idValue = ((HtmlTag) (token.getValue())).getAttribute(KEY_ID);
if (idValue != null) {
inBugzillaBody = idValue.equals("bugzilla-body"); //$NON-NLS-1$
} else {
inBugzillaBody = false;
}
}
if (inBugzillaBody) {
if (token.getType() == Token.TAG) {
if (((HtmlTag) (token.getValue())).getTagType() == Tag.DL) {
if (((HtmlTag) (token.getValue())).isEndTag()) {
dlLevel--;
} else {
dlLevel++;
}
} else if (((HtmlTag) (token.getValue())).getTagType() == Tag.DT) {
isDT = !((HtmlTag) (token.getValue())).isEndTag();
if (isDT) {
if (dlLevel == 1) {
dt1 = " "; //$NON-NLS-1$
} else if (dlLevel == 2) {
dt2 = " "; //$NON-NLS-1$
}
}
} else if (((HtmlTag) (token.getValue())).getTagType() == Tag.CODE) {
if (isCODE) {
if (codeString.length() > 0) {
codeString = codeString.replace("&#64;", "@"); //$NON-NLS-1$ //$NON-NLS-2$
response.addResponseData(dt1, dt2, codeString);
}
codeString = ""; //$NON-NLS-1$
}
isCODE = !((HtmlTag) (token.getValue())).isEndTag();
}
} else {
if (isDT) {
if (dlLevel == 1) {
dt1 += (" " + token.getValue()); //$NON-NLS-1$
} else if (dlLevel == 2) {
dt2 += (" " + token.getValue()); //$NON-NLS-1$
}
} else if (isCODE) {
codeString += ("" + token.getValue()); //$NON-NLS-1$
}
}
}
}
} catch (ParseException e) {
throw new CoreException(new BugzillaStatus(IStatus.ERROR, BugzillaCorePlugin.ID_PLUGIN,
RepositoryStatus.ERROR_INTERNAL, "Unable to parse response from " + repositoryUrl.toString() + ".")); //$NON-NLS-1$ //$NON-NLS-2$
}
}
/**
* Currently only necessary for testing. Allows setting of the descriptor file property.
*
* @param bugzillaDescriptorFile
* @param canonicalPath
*/
public void setDescriptorFile(String canonicalPath) {
configParameters.put(IBugzillaConstants.BUGZILLA_DESCRIPTOR_FILE, canonicalPath);
}
private BugzillaXmlRpcClient getXmlRpcClient() {
boolean useXMLRPC = Boolean.parseBoolean(configParameters.get(IBugzillaConstants.BUGZILLA_USE_XMLRPC));
if (useXMLRPC && xmlRpcClient == null) {
WebLocation webLocation = new WebLocation(this.repositoryUrl + "/xmlrpc.cgi"); //$NON-NLS-1$
String username = ""; //$NON-NLS-1$
String password = ""; //$NON-NLS-1$
if (location.getCredentials(AuthenticationType.REPOSITORY) != null) {
username = location.getCredentials(AuthenticationType.REPOSITORY).getUserName();
}
if (location.getCredentials(AuthenticationType.REPOSITORY) != null) {
password = location.getCredentials(AuthenticationType.REPOSITORY).getPassword();
}
webLocation.setCredentials(AuthenticationType.REPOSITORY, username, password);
xmlRpcClient = new BugzillaXmlRpcClient(webLocation);
xmlRpcClient.setContentTypeCheckingEnabled(true);
}
return xmlRpcClient;
}
public List<BugHistory> getBugHistory(String id, IProgressMonitor monitor) throws CoreException {
int bugId = Integer.parseInt(id);
try {
BugzillaXmlRpcClient client = getXmlRpcClient();
if (client == null) {
throw new CoreException(new Status(IStatus.WARNING, BugzillaCorePlugin.ID_PLUGIN,
"XMLRPC is not available")); //$NON-NLS-1$
}
return client.getHistory(new Integer[] { bugId }, monitor);
} catch (XmlRpcException e) {
throw new CoreException(
new Status(IStatus.WARNING, BugzillaCorePlugin.ID_PLUGIN, "XMLRPC is not installed")); //$NON-NLS-1$
}
}
/**
* Copies all bytes in the given source stream to the given destination stream. Neither streams are closed.
*
* @param source
* the given source stream
* @param destination
* the given destination stream
* @throws IOException
* in case of error
*/
private static void transferData(InputStream in, OutputStream out) throws IOException {
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
}
/**
* Returns the given file path with its separator character changed from the given old separator to the given new
* separator.
*
* @param path
* a file path
* @param oldSeparator
* a path separator character
* @param newSeparator
* a path separator character
* @return the file path with its separator character changed from the given old separator to the given new
* separator
*/
public static String changeSeparator(String path, char oldSeparator, char newSeparator) {
return path.replace(oldSeparator, newSeparator);
}
public void downloadXMLTransFile(String transFile, IProgressMonitor monitor) throws IOException, CoreException {
monitor = Policy.monitorFor(monitor);
String loginUrl = repositoryUrl + "/xml_transition_file.mylyn"; //$NON-NLS-1$
GzipGetMethod method = null;
try {
method = getConnect(loginUrl, monitor);
InputStream input = null;
File file = new File(changeSeparator(transFile, '/', File.separatorChar));
file.getParentFile().mkdirs();
FileOutputStream output = new FileOutputStream(transFile);
input = getResponseStream(method, monitor);
transferData(input, output);
} finally {
if (method != null) {
WebUtil.releaseConnection(method, monitor);
}
}
}
private void parseResultConfirmMatch(HtmlStreamTokenizer tokenizer, BugzillaStatus status) throws IOException,
CoreException {
boolean isSelect = false;
String name = ""; //$NON-NLS-1$
String value = ""; //$NON-NLS-1$
try {
for (Token token = tokenizer.nextToken(); token.getType() != Token.EOF; token = tokenizer.nextToken()) {
if (token.getType() == Token.TAG && ((HtmlTag) (token.getValue())).getTagType() == Tag.SELECT
&& !((HtmlTag) (token.getValue())).isEndTag()) {
isSelect = true;
name = ((HtmlTag) (token.getValue())).getAttribute("id"); //$NON-NLS-1$
continue;
}
if (isSelect) {
if (token.getType() == Token.TAG && ((HtmlTag) (token.getValue())).getTagType() == Tag.OPTION
&& !((HtmlTag) (token.getValue())).isEndTag()) {
value = ((HtmlTag) (token.getValue())).getAttribute("value"); //$NON-NLS-1$
status.addResponseData(name, value);
}
if (token.getType() == Token.TAG && ((HtmlTag) token.getValue()).getTagType() == Tag.SELECT
&& ((HtmlTag) token.getValue()).isEndTag()) {
isSelect = false;
}
}
}
throw new CoreException(status);
} catch (ParseException e) {
throw new CoreException(new BugzillaStatus(IStatus.ERROR, BugzillaCorePlugin.ID_PLUGIN,
RepositoryStatus.ERROR_INTERNAL, "Unable to parse response from " + repositoryUrl.toString() + ".")); //$NON-NLS-1$//$NON-NLS-2$
}
}
private void parseResultMatchFailed(HtmlStreamTokenizer tokenizer, BugzillaStatus status) throws IOException,
CoreException {
boolean isDT = false;
String dtString = ""; //$NON-NLS-1$
String lastDTValue = ""; //$NON-NLS-1$
boolean isDiv = false;
String divString = ""; //$NON-NLS-1$
try {
for (Token token = tokenizer.nextToken(); token.getType() != Token.EOF; token = tokenizer.nextToken()) {
if (token.getType() == Token.TAG && ((HtmlTag) (token.getValue())).getTagType() == Tag.TD
&& ((HtmlTag) (token.getValue())).isEndTag()) {
isDT = false;
if (!dtString.equals("")) { //$NON-NLS-1$
lastDTValue = dtString;
}
dtString = ""; //$NON-NLS-1$
continue;
}
if (token.getType() == Token.TAG && ((HtmlTag) (token.getValue())).getTagType() == Tag.DIV
&& ((HtmlTag) (token.getValue())).isEndTag()) {
isDiv = false;
if (divString.length() > 4) {
if (lastDTValue.equals("CC:")) { //$NON-NLS-1$
lastDTValue = "newcc"; //$NON-NLS-1$
}
if (lastDTValue.equals("Assignee:")) { //$NON-NLS-1$
lastDTValue = "assigned_to"; //$NON-NLS-1$
}
if (lastDTValue.equals("QAContact:")) { //$NON-NLS-1$
lastDTValue = "qa_contact"; //$NON-NLS-1$
}
int start = divString.indexOf("</b>"); //$NON-NLS-1$
int optionValue = divString.indexOf("<option value=\"", start + 4); //$NON-NLS-1$
String value = ""; //$NON-NLS-1$
if (optionValue == -1) {
int startText = divString.indexOf(">", start + 4) + 1; //$NON-NLS-1$
int endText = divString.indexOf("<", startText + 1); //$NON-NLS-1$
String temp = divString.substring(startText, endText);
value = divString.substring(5, start) + temp;
status.addResponseData(lastDTValue, "#msg#" + value); //$NON-NLS-1$
} else {
while (optionValue != -1) {
int endText = divString.indexOf("\">", optionValue + 1); //$NON-NLS-1$
value = divString.substring(optionValue + 15, endText);
value = value.replace("&#64;", "@"); //$NON-NLS-1$ //$NON-NLS-2$
status.addResponseData(lastDTValue, value);
optionValue = divString.indexOf("<option value=\"", endText + 1); //$NON-NLS-1$
}
}
}
dtString = ""; //$NON-NLS-1$
divString = ""; //$NON-NLS-1$
continue;
}
if (isDiv) {
divString += (" " + token.getValue()); //$NON-NLS-1$
}
if (isDT) {
if (token.getType() == Token.TAG && ((HtmlTag) (token.getValue())).getTagType() == Tag.DIV
&& !((HtmlTag) (token.getValue())).isEndTag()) {
isDiv = true;
divString = ""; //$NON-NLS-1$
} else {
dtString += token.getValue();
}
}
if (token.getType() == Token.TAG && ((HtmlTag) (token.getValue())).getTagType() == Tag.TD
&& !((HtmlTag) (token.getValue())).isEndTag()) {
isDT = true;
continue;
}
}
throw new CoreException(status);
} catch (ParseException e) {
throw new CoreException(new BugzillaStatus(IStatus.ERROR, BugzillaCorePlugin.ID_PLUGIN,
RepositoryStatus.ERROR_INTERNAL, "Unable to parse response from " + repositoryUrl.toString() + ".")); //$NON-NLS-1$ //$NON-NLS-2$
}
}
}