001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. The ASF licenses this file to You
004: * under the Apache License, Version 2.0 (the "License"); you may not
005: * use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License. For additional information regarding
015: * copyright in this work, please see the NOTICE file in the top level
016: * directory of this distribution.
017: */
018:
019: package org.apache.roller.ui.rendering.servlets;
020:
021: import java.io.IOException;
022: import java.io.PrintWriter;
023: import java.sql.Timestamp;
024: import java.util.Date;
025: import javax.servlet.ServletException;
026: import javax.servlet.http.HttpServlet;
027: import javax.servlet.http.HttpServletRequest;
028: import javax.servlet.http.HttpServletResponse;
029: import org.apache.commons.logging.Log;
030: import org.apache.commons.logging.LogFactory;
031: import org.apache.roller.RollerException;
032: import org.apache.roller.config.RollerRuntimeConfig;
033: import org.apache.roller.business.RollerFactory;
034: import org.apache.roller.business.UserManager;
035: import org.apache.roller.business.WeblogManager;
036: import org.apache.roller.pojos.CommentData;
037: import org.apache.roller.pojos.WeblogEntryData;
038: import org.apache.roller.pojos.WebsiteData;
039: import org.apache.roller.ui.rendering.util.WeblogTrackbackRequest;
040: import org.apache.roller.util.LinkbackExtractor;
041: import org.apache.roller.util.SpamChecker;
042: import org.apache.roller.util.URLUtilities;
043: import org.apache.roller.util.cache.CacheManager;
044: import org.apache.struts.util.RequestUtils;
045:
046: /**
047: * Roller's Trackback server implementation. POSTing to this Servlet will add a
048: * Trackback to a Weblog Entry. For more info on Trackback, read the spec:
049: * <a href="http://www.movabletype.org/docs/mttrackback.html>MT Trackback</a>.
050: *
051: * @web.servlet name="TrackbackServlet"
052: * @web.servlet-mapping url-pattern="/roller-ui/rendering/trackback/*"
053: */
054: public class TrackbackServlet extends HttpServlet {
055:
056: private static Log logger = LogFactory
057: .getLog(TrackbackServlet.class);
058:
059: /**
060: * Handle incoming http GET requests.
061: *
062: * The TrackbackServlet does not support GET requests, it's a 404.
063: */
064: public void doGet(HttpServletRequest request,
065: HttpServletResponse response) throws IOException,
066: ServletException {
067:
068: response.sendError(HttpServletResponse.SC_NOT_FOUND);
069: }
070:
071: /**
072: * Service incoming POST requests.
073: *
074: * Here we handle incoming trackback posts.
075: */
076: public void doPost(HttpServletRequest request,
077: HttpServletResponse response) throws ServletException,
078: IOException {
079:
080: String error = null;
081: PrintWriter pw = response.getWriter();
082:
083: WebsiteData weblog = null;
084: WeblogEntryData entry = null;
085:
086: WeblogTrackbackRequest trackbackRequest = null;
087: if (!RollerRuntimeConfig
088: .getBooleanProperty("users.trackbacks.enabled")) {
089: // TODO: i18n
090: error = "Trackbacks are disabled for this site";
091: } else {
092:
093: try {
094: trackbackRequest = new WeblogTrackbackRequest(request);
095:
096: if ((trackbackRequest.getTitle() == null)
097: || "".equals(trackbackRequest.getTitle())) {
098: trackbackRequest
099: .setTitle(trackbackRequest.getUrl());
100: }
101:
102: if (trackbackRequest.getExcerpt() == null) {
103: trackbackRequest.setExcerpt("");
104: } else if (trackbackRequest.getExcerpt().length() >= 255) {
105: trackbackRequest.setExcerpt(trackbackRequest
106: .getExcerpt().substring(0, 252)
107: + "...");
108: }
109:
110: // lookup weblog specified by comment request
111: UserManager uMgr = RollerFactory.getRoller()
112: .getUserManager();
113: weblog = uMgr.getWebsiteByHandle(trackbackRequest
114: .getWeblogHandle());
115:
116: if (weblog == null) {
117: throw new RollerException(
118: "unable to lookup weblog: "
119: + trackbackRequest
120: .getWeblogHandle());
121: }
122:
123: // lookup entry specified by comment request
124: WeblogManager weblogMgr = RollerFactory.getRoller()
125: .getWeblogManager();
126: entry = weblogMgr.getWeblogEntryByAnchor(weblog,
127: trackbackRequest.getWeblogAnchor());
128:
129: if (entry == null) {
130: throw new RollerException(
131: "unable to lookup entry: "
132: + trackbackRequest
133: .getWeblogAnchor());
134: }
135:
136: } catch (Exception e) {
137: // some kind of error parsing the request or looking up weblog
138: logger.debug("error creating trackback request", e);
139: error = e.getMessage();
140: }
141: }
142:
143: if (error != null) {
144: pw.println(this .getErrorResponse(error));
145: return;
146: }
147:
148: try {
149: boolean verified = true;
150:
151: // check if trackbacks are allowed for this entry
152: // this checks site-wide settings, weblog settings, and entry settings
153: if (entry != null && entry.getCommentsStillAllowed()
154: && entry.isPublished()) {
155:
156: // Track trackbacks as comments
157: CommentData comment = new CommentData();
158: comment.setContent("[Trackback] "
159: + trackbackRequest.getExcerpt());
160: comment.setName(trackbackRequest.getBlogName());
161: comment.setUrl(trackbackRequest.getUrl());
162: comment.setWeblogEntry(entry);
163: comment.setNotify(Boolean.FALSE);
164: comment
165: .setPostTime(new Timestamp(new Date().getTime()));
166:
167: // If comment contains blacklisted text, mark as spam
168: SpamChecker checker = new SpamChecker();
169: if (checker.checkTrackback(comment)) {
170: comment.setSpam(Boolean.TRUE);
171: logger.debug("Trackback blacklisted: "
172: + comment.getUrl());
173: error = "REJECTED: trackback contains spam words";
174: }
175: // Else, if trackback verification is on...
176: else if (RollerRuntimeConfig
177: .getBooleanProperty("site.trackbackVerification.enabled")) {
178:
179: // ...ensure trackbacker actually links to us
180: LinkbackExtractor linkback = new LinkbackExtractor(
181: comment.getUrl(), URLUtilities
182: .getWeblogEntryURL(weblog, null,
183: entry.getAnchor(), true));
184: if (linkback.getExcerpt() == null) {
185: comment.setPending(Boolean.TRUE);
186: comment.setApproved(Boolean.FALSE);
187: verified = false;
188: // if we can't verify trackback, then reject it
189: error = "REJECTED: trackback failed verification";
190: logger.debug("Trackback failed verification: "
191: + comment.getUrl());
192: }
193: }
194:
195: if (error == null) {
196: // If comment moderation is on, set comment as pending
197: if (verified
198: && weblog.getCommentModerationRequired()) {
199: comment.setPending(Boolean.TRUE);
200: comment.setApproved(Boolean.FALSE);
201: } else if (verified) {
202: comment.setPending(Boolean.FALSE);
203: comment.setApproved(Boolean.TRUE);
204: }
205:
206: // save, commit, send response
207: WeblogManager mgr = RollerFactory.getRoller()
208: .getWeblogManager();
209: mgr.saveComment(comment);
210: RollerFactory.getRoller().flush();
211:
212: // only invalidate the cache if comment isn't moderated
213: if (!weblog.getCommentModerationRequired()) {
214: // Clear all caches associated with comment
215: CacheManager.invalidate(comment);
216: }
217:
218: // Send email notifications
219: String rootURL = RollerRuntimeConfig
220: .getAbsoluteContextURL();
221: if (rootURL == null || rootURL.trim().length() == 0) {
222: rootURL = RequestUtils.serverURL(request)
223: + request.getContextPath();
224: }
225: CommentServlet.sendEmailNotification(comment,
226: rootURL);
227:
228: if (comment.getPending().booleanValue()) {
229: pw
230: .println(this
231: .getSuccessResponse("Trackback submitted to moderator"));
232: } else {
233: pw
234: .println(this
235: .getSuccessResponse("Trackback accepted"));
236: }
237: }
238:
239: } else if (entry != null) {
240: // TODO: i18n
241: error = "Comments and Trackbacks are disabled for the entry you specified.";
242: } else {
243: // TODO: i18n
244: error = "Entry not specified.";
245: }
246:
247: } catch (Exception e) {
248: error = e.getMessage();
249: if (error == null) {
250: error = e.getClass().getName();
251: }
252: }
253:
254: if (error != null) {
255: pw.println(this .getErrorResponse(error));
256: }
257:
258: }
259:
260: private String getSuccessResponse(String message) {
261:
262: StringBuffer output = new StringBuffer();
263:
264: output
265: .append("<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>");
266: output.append("<response>");
267: output.append("<error>0</error>");
268: output.append("<message>");
269: output.append(message);
270: output.append("</message>");
271: output.append("</response>");
272:
273: return output.toString();
274: }
275:
276: private String getErrorResponse(String message) {
277:
278: StringBuffer output = new StringBuffer();
279:
280: output
281: .append("<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>");
282: output.append("<response>");
283: output.append("<error>1</error>");
284: output.append("<message>ERROR: ");
285: output.append(message);
286: output.append("</message>");
287: output.append("</response>");
288:
289: return output.toString();
290: }
291:
292: }
|