001: /**
002: * Copyright (c) 2003-2007, David A. Czarnecki
003: * All rights reserved.
004: *
005: * Redistribution and use in source and binary forms, with or without
006: * modification, are permitted provided that the following conditions are met:
007: *
008: * Redistributions of source code must retain the above copyright notice, this list of conditions and the
009: * following disclaimer.
010: * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
011: * following disclaimer in the documentation and/or other materials provided with the distribution.
012: * Neither the name of "David A. Czarnecki" and "blojsom" nor the names of its contributors may be used to
013: * endorse or promote products derived from this software without specific prior written permission.
014: * Products derived from this software may not be called "blojsom", nor may "blojsom" appear in their name,
015: * without prior written permission of David A. Czarnecki.
016: *
017: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
018: * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
019: * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
020: * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
021: * EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
022: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
023: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
024: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
025: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
026: * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
027: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
028: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
029: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
030: */package org.blojsom.plugin.akismet;
031:
032: import net.sf.akismet.Akismet;
033: import org.apache.commons.logging.Log;
034: import org.apache.commons.logging.LogFactory;
035: import org.blojsom.blog.Blog;
036: import org.blojsom.blog.Entry;
037: import org.blojsom.event.Event;
038: import org.blojsom.event.EventBroadcaster;
039: import org.blojsom.event.Listener;
040: import org.blojsom.plugin.Plugin;
041: import org.blojsom.plugin.PluginException;
042: import org.blojsom.plugin.comment.CommentModerationPlugin;
043: import org.blojsom.plugin.comment.CommentPlugin;
044: import org.blojsom.plugin.comment.event.CommentResponseSubmissionEvent;
045: import org.blojsom.plugin.comment.event.CommentMarkedSpamEvent;
046: import org.blojsom.plugin.comment.event.CommentUnmarkedSpamEvent;
047: import org.blojsom.plugin.pingback.event.PingbackResponseSubmissionEvent;
048: import org.blojsom.plugin.pingback.event.PingbackMarkedSpamEvent;
049: import org.blojsom.plugin.pingback.event.PingbackUnmarkedSpamEvent;
050: import org.blojsom.plugin.pingback.PingbackPlugin;
051: import org.blojsom.plugin.response.event.ResponseSubmissionEvent;
052: import org.blojsom.plugin.trackback.TrackbackModerationPlugin;
053: import org.blojsom.plugin.trackback.TrackbackPlugin;
054: import org.blojsom.plugin.trackback.event.TrackbackResponseSubmissionEvent;
055: import org.blojsom.plugin.trackback.event.TrackbackUnmarkedSpamEvent;
056: import org.blojsom.plugin.trackback.event.TrackbackMarkedSpamEvent;
057: import org.blojsom.util.BlojsomUtils;
058:
059: import javax.servlet.http.HttpServletRequest;
060: import javax.servlet.http.HttpServletResponse;
061: import java.util.Map;
062:
063: /**
064: * Akismet moderation plugin
065: *
066: * @author David Czarnecki
067: * @version $Id: AkismetModerationPlugin.java,v 1.8 2007/01/17 01:15:46 czarneckid Exp $
068: * @since blojsom 3.0
069: */
070: public class AkismetModerationPlugin implements Plugin, Listener {
071:
072: private Log _logger = LogFactory
073: .getLog(AkismetModerationPlugin.class);
074:
075: // Initialization parameters
076: private static final String AKISMET_PLUGIN_API_KEY_IP = "akismet-plugin-api-key";
077: private static final String AKISMET_PLUGIN_DELETE_SPAM_IP = "akismet-plugin-delete-spam";
078: private static final String AKISMET_PLUGIN_AUTOMATIC_APPROVAL_IP = "akismet-plugin-automatic-approval";
079: private static final boolean DELETE_SPAM_DEFAULT = false;
080:
081: // Context variables
082: private static final String AKISMET_PLUGIN_RESPONSE = "AKISMET_PLUGIN_RESPONSE";
083:
084: private EventBroadcaster _eventBroadcaster;
085:
086: /**
087: * Construct a new instance of the Akismet moderation plugin
088: */
089: public AkismetModerationPlugin() {
090: }
091:
092: /**
093: * Set the {@link org.blojsom.event.EventBroadcaster} event broadcaster
094: *
095: * @param eventBroadcaster {@link org.blojsom.event.EventBroadcaster}
096: */
097: public void setEventBroadcaster(EventBroadcaster eventBroadcaster) {
098: _eventBroadcaster = eventBroadcaster;
099: }
100:
101: /**
102: * Initialize this plugin. This method only called when the plugin is instantiated.
103: *
104: * @throws org.blojsom.plugin.PluginException
105: * If there is an error initializing the plugin
106: */
107: public void init() throws PluginException {
108: _eventBroadcaster.addListener(this );
109: }
110:
111: /**
112: * Process the blog entries
113: *
114: * @param httpServletRequest Request
115: * @param httpServletResponse Response
116: * @param blog {@link Blog} instance
117: * @param context Context
118: * @param entries Blog entries retrieved for the particular request
119: * @return Modified set of blog entries
120: * @throws PluginException If there is an error processing the blog entries
121: */
122: public Entry[] process(HttpServletRequest httpServletRequest,
123: HttpServletResponse httpServletResponse, Blog blog,
124: Map context, Entry[] entries) throws PluginException {
125: return entries;
126: }
127:
128: /**
129: * Perform any cleanup for the plugin. Called after {@link #process}.
130: *
131: * @throws org.blojsom.plugin.PluginException
132: * If there is an error performing cleanup for this plugin
133: */
134: public void cleanup() throws PluginException {
135: }
136:
137: /**
138: * Called when BlojsomServlet is taken out of service
139: *
140: * @throws org.blojsom.plugin.PluginException
141: * If there is an error in finalizing this plugin
142: */
143: public void destroy() throws PluginException {
144: }
145:
146: /**
147: * Handle an event broadcast from another component
148: *
149: * @param event {@link org.blojsom.event.Event} to be handled
150: */
151: public void handleEvent(Event event) {
152: }
153:
154: /**
155: * Process an event from another component
156: *
157: * @param event {@link org.blojsom.event.Event} to be handled
158: */
159: public void processEvent(Event event) {
160: if (event instanceof ResponseSubmissionEvent) {
161: ResponseSubmissionEvent responseSubmissionEvent = (ResponseSubmissionEvent) event;
162: Blog blog = responseSubmissionEvent.getBlog();
163:
164: String akismetAPIKey = blog
165: .getProperty(AKISMET_PLUGIN_API_KEY_IP);
166: if (BlojsomUtils.checkNullOrBlank(akismetAPIKey)) {
167: if (_logger.isInfoEnabled()) {
168: _logger
169: .info("No Akismet API key provided for blog property: "
170: + AKISMET_PLUGIN_API_KEY_IP);
171: }
172: } else {
173: Akismet akismet = new Akismet(akismetAPIKey, blog
174: .getBlogURL());
175: String responseType = Akismet.COMMENT_TYPE_BLANK;
176:
177: if (responseSubmissionEvent instanceof CommentResponseSubmissionEvent) {
178: responseType = Akismet.COMMENT_TYPE_COMMENT;
179: } else if (responseSubmissionEvent instanceof TrackbackResponseSubmissionEvent) {
180: responseType = Akismet.COMMENT_TYPE_TRACKBACK;
181: } else if (responseSubmissionEvent instanceof PingbackResponseSubmissionEvent) {
182: responseType = Akismet.COMMENT_TYPE_PINGBACK;
183: }
184:
185: // Check the content from Akismet
186: HttpServletRequest httpServletRequest = responseSubmissionEvent
187: .getHttpServletRequest();
188: Map metaData = responseSubmissionEvent.getMetaData();
189:
190: StringBuffer entryLink = new StringBuffer().append(
191: blog.getBlogURL()).append(
192: responseSubmissionEvent.getEntry()
193: .getCategory()).append(
194: responseSubmissionEvent.getEntry()
195: .getPostSlug());
196:
197: boolean isSpam = akismet.commentCheck(
198: httpServletRequest.getRemoteAddr(),
199: httpServletRequest.getHeader("User-Agent"),
200: httpServletRequest.getHeader("Referer"),
201: entryLink.toString(), responseType,
202: responseSubmissionEvent.getSubmitter(),
203: responseSubmissionEvent.getSubmitterItem1(),
204: responseSubmissionEvent.getSubmitterItem2(),
205: responseSubmissionEvent.getContent(), null);
206:
207: metaData.put(AKISMET_PLUGIN_RESPONSE, Boolean
208: .toString(isSpam));
209:
210: // If Akismet identifies the content as spam, process for moderation or deletion accordingly
211: if (isSpam) {
212: boolean deleteSpam = DELETE_SPAM_DEFAULT;
213:
214: String deleteSpamValue = responseSubmissionEvent
215: .getBlog().getProperty(
216: AKISMET_PLUGIN_DELETE_SPAM_IP);
217: if (!BlojsomUtils.checkNullOrBlank(deleteSpamValue)) {
218: deleteSpam = Boolean.valueOf(deleteSpamValue)
219: .booleanValue();
220: }
221:
222: if (!deleteSpam) {
223: if (_logger.isDebugEnabled()) {
224: _logger
225: .debug("Marking response for moderation");
226: }
227: } else {
228: if (_logger.isDebugEnabled()) {
229: _logger
230: .debug("Marking response for automatic deletion");
231: }
232: }
233:
234: if (responseSubmissionEvent instanceof CommentResponseSubmissionEvent) {
235: if (!deleteSpam) {
236: metaData
237: .put(
238: CommentModerationPlugin.BLOJSOM_COMMENT_MODERATION_PLUGIN_APPROVED,
239: Boolean.FALSE.toString());
240: } else {
241: metaData
242: .put(
243: CommentPlugin.BLOJSOM_PLUGIN_COMMENT_METADATA_DESTROY,
244: Boolean.TRUE);
245: }
246: } else if (responseSubmissionEvent instanceof TrackbackResponseSubmissionEvent) {
247: if (!deleteSpam) {
248: metaData
249: .put(
250: TrackbackModerationPlugin.BLOJSOM_TRACKBACK_MODERATION_PLUGIN_APPROVED,
251: Boolean.FALSE.toString());
252: } else {
253: metaData
254: .put(
255: TrackbackPlugin.BLOJSOM_PLUGIN_TRACKBACK_METADATA_DESTROY,
256: Boolean.TRUE);
257: }
258: } else if (responseSubmissionEvent instanceof PingbackResponseSubmissionEvent) {
259: if (!deleteSpam) {
260: metaData
261: .put(
262: PingbackPlugin.BLOJSOM_PINGBACK_PLUGIN_APPROVED,
263: Boolean.FALSE.toString());
264: } else {
265: metaData
266: .put(
267: PingbackPlugin.BLOJSOM_PLUGIN_PINGBACK_METADATA_DESTROY,
268: Boolean.TRUE);
269: }
270: }
271: } else {
272: boolean automaticApproval = Boolean
273: .valueOf(
274: blog
275: .getProperty(AKISMET_PLUGIN_AUTOMATIC_APPROVAL_IP))
276: .booleanValue();
277: if (automaticApproval) {
278: if (responseSubmissionEvent instanceof CommentResponseSubmissionEvent) {
279: if (!metaData
280: .containsKey(CommentPlugin.BLOJSOM_PLUGIN_COMMENT_METADATA_DESTROY)) {
281: metaData
282: .put(
283: CommentModerationPlugin.BLOJSOM_COMMENT_MODERATION_PLUGIN_APPROVED,
284: Boolean.TRUE.toString());
285: }
286: } else if (responseSubmissionEvent instanceof TrackbackResponseSubmissionEvent) {
287: if (!metaData
288: .containsKey(TrackbackPlugin.BLOJSOM_PLUGIN_TRACKBACK_METADATA_DESTROY)) {
289: metaData
290: .put(
291: TrackbackModerationPlugin.BLOJSOM_TRACKBACK_MODERATION_PLUGIN_APPROVED,
292: Boolean.TRUE.toString());
293: }
294: } else if (responseSubmissionEvent instanceof PingbackResponseSubmissionEvent) {
295: if (!metaData
296: .containsKey(PingbackPlugin.BLOJSOM_PLUGIN_PINGBACK_METADATA_DESTROY)) {
297: metaData
298: .put(
299: PingbackPlugin.BLOJSOM_PINGBACK_PLUGIN_APPROVED,
300: Boolean.TRUE.toString());
301: }
302: }
303: }
304: }
305:
306: responseSubmissionEvent.setMetaData(metaData);
307: }
308: } else if (event instanceof CommentMarkedSpamEvent) {
309: CommentMarkedSpamEvent commentMarkedSpamEvent = (CommentMarkedSpamEvent) event;
310: Blog blog = commentMarkedSpamEvent.getBlog();
311:
312: String akismetAPIKey = blog
313: .getProperty(AKISMET_PLUGIN_API_KEY_IP);
314: if (BlojsomUtils.checkNullOrBlank(akismetAPIKey)) {
315: if (_logger.isInfoEnabled()) {
316: _logger
317: .info("No Akismet API key provided for blog property: "
318: + AKISMET_PLUGIN_API_KEY_IP);
319: }
320: } else {
321: Akismet akismet = new Akismet(akismetAPIKey, blog
322: .getBlogURL());
323: String responseType = Akismet.COMMENT_TYPE_COMMENT;
324: StringBuffer permalink = new StringBuffer();
325: permalink.append(blog.getBlogURL()).append("/").append(
326: commentMarkedSpamEvent.getEntry()
327: .getBlogCategory().getName())
328: .append(
329: commentMarkedSpamEvent.getEntry()
330: .getPostSlug());
331:
332: akismet.submitSpam(commentMarkedSpamEvent.getComment()
333: .getIp(), null, null, permalink.toString(),
334: responseType, commentMarkedSpamEvent
335: .getComment().getAuthor(),
336: commentMarkedSpamEvent.getComment()
337: .getAuthorEmail(),
338: commentMarkedSpamEvent.getComment()
339: .getAuthorURL(), commentMarkedSpamEvent
340: .getComment().getComment(), null);
341: }
342: } else if (event instanceof CommentUnmarkedSpamEvent) {
343: CommentUnmarkedSpamEvent commentUnmarkedSpamEvent = (CommentUnmarkedSpamEvent) event;
344: Blog blog = commentUnmarkedSpamEvent.getBlog();
345:
346: String akismetAPIKey = blog
347: .getProperty(AKISMET_PLUGIN_API_KEY_IP);
348: if (BlojsomUtils.checkNullOrBlank(akismetAPIKey)) {
349: if (_logger.isInfoEnabled()) {
350: _logger
351: .info("No Akismet API key provided for blog property: "
352: + AKISMET_PLUGIN_API_KEY_IP);
353: }
354: } else {
355: Akismet akismet = new Akismet(akismetAPIKey, blog
356: .getBlogURL());
357: String responseType = Akismet.COMMENT_TYPE_COMMENT;
358: StringBuffer permalink = new StringBuffer();
359: permalink.append(blog.getBlogURL()).append("/").append(
360: commentUnmarkedSpamEvent.getEntry()
361: .getBlogCategory().getName()).append(
362: commentUnmarkedSpamEvent.getEntry()
363: .getPostSlug());
364:
365: akismet.submitHam(commentUnmarkedSpamEvent.getComment()
366: .getIp(), null, null, permalink.toString(),
367: responseType, commentUnmarkedSpamEvent
368: .getComment().getAuthor(),
369: commentUnmarkedSpamEvent.getComment()
370: .getAuthorEmail(),
371: commentUnmarkedSpamEvent.getComment()
372: .getAuthorURL(),
373: commentUnmarkedSpamEvent.getComment()
374: .getComment(), null);
375: }
376: } else if (event instanceof TrackbackMarkedSpamEvent) {
377: TrackbackMarkedSpamEvent trackbackMarkedSpamEvent = (TrackbackMarkedSpamEvent) event;
378: Blog blog = trackbackMarkedSpamEvent.getBlog();
379:
380: String akismetAPIKey = blog
381: .getProperty(AKISMET_PLUGIN_API_KEY_IP);
382: if (BlojsomUtils.checkNullOrBlank(akismetAPIKey)) {
383: if (_logger.isInfoEnabled()) {
384: _logger
385: .info("No Akismet API key provided for blog property: "
386: + AKISMET_PLUGIN_API_KEY_IP);
387: }
388: } else {
389: Akismet akismet = new Akismet(akismetAPIKey, blog
390: .getBlogURL());
391: String responseType = Akismet.COMMENT_TYPE_TRACKBACK;
392: StringBuffer permalink = new StringBuffer();
393: permalink.append(blog.getBlogURL()).append("/").append(
394: trackbackMarkedSpamEvent.getEntry()
395: .getBlogCategory().getName()).append(
396: trackbackMarkedSpamEvent.getEntry()
397: .getPostSlug());
398:
399: akismet.submitSpam(trackbackMarkedSpamEvent
400: .getTrackback().getIp(), null, null, permalink
401: .toString(), responseType,
402: trackbackMarkedSpamEvent.getTrackback()
403: .getTitle(), trackbackMarkedSpamEvent
404: .getTrackback().getBlogName(),
405: trackbackMarkedSpamEvent.getTrackback()
406: .getUrl(), trackbackMarkedSpamEvent
407: .getTrackback().getExcerpt(), null);
408: }
409: } else if (event instanceof TrackbackUnmarkedSpamEvent) {
410: TrackbackUnmarkedSpamEvent trackbackUnmarkedSpamEvent = (TrackbackUnmarkedSpamEvent) event;
411: Blog blog = trackbackUnmarkedSpamEvent.getBlog();
412:
413: String akismetAPIKey = blog
414: .getProperty(AKISMET_PLUGIN_API_KEY_IP);
415: if (BlojsomUtils.checkNullOrBlank(akismetAPIKey)) {
416: if (_logger.isInfoEnabled()) {
417: _logger
418: .info("No Akismet API key provided for blog property: "
419: + AKISMET_PLUGIN_API_KEY_IP);
420: }
421: } else {
422: Akismet akismet = new Akismet(akismetAPIKey, blog
423: .getBlogURL());
424: String responseType = Akismet.COMMENT_TYPE_TRACKBACK;
425: StringBuffer permalink = new StringBuffer();
426: permalink.append(blog.getBlogURL()).append("/").append(
427: trackbackUnmarkedSpamEvent.getEntry()
428: .getBlogCategory().getName()).append(
429: trackbackUnmarkedSpamEvent.getEntry()
430: .getPostSlug());
431:
432: akismet.submitHam(trackbackUnmarkedSpamEvent
433: .getTrackback().getIp(), null, null, permalink
434: .toString(), responseType,
435: trackbackUnmarkedSpamEvent.getTrackback()
436: .getTitle(), trackbackUnmarkedSpamEvent
437: .getTrackback().getBlogName(),
438: trackbackUnmarkedSpamEvent.getTrackback()
439: .getUrl(), trackbackUnmarkedSpamEvent
440: .getTrackback().getExcerpt(), null);
441: }
442: } else if (event instanceof PingbackMarkedSpamEvent) {
443: PingbackMarkedSpamEvent pingbackMarkedSpamEvent = (PingbackMarkedSpamEvent) event;
444: Blog blog = pingbackMarkedSpamEvent.getBlog();
445:
446: String akismetAPIKey = blog
447: .getProperty(AKISMET_PLUGIN_API_KEY_IP);
448: if (BlojsomUtils.checkNullOrBlank(akismetAPIKey)) {
449: if (_logger.isInfoEnabled()) {
450: _logger
451: .info("No Akismet API key provided for blog property: "
452: + AKISMET_PLUGIN_API_KEY_IP);
453: }
454: } else {
455: Akismet akismet = new Akismet(akismetAPIKey, blog
456: .getBlogURL());
457: String responseType = Akismet.COMMENT_TYPE_PINGBACK;
458: StringBuffer permalink = new StringBuffer();
459: permalink.append(blog.getBlogURL()).append("/").append(
460: pingbackMarkedSpamEvent.getEntry()
461: .getBlogCategory().getName()).append(
462: pingbackMarkedSpamEvent.getEntry()
463: .getPostSlug());
464:
465: akismet.submitSpam(pingbackMarkedSpamEvent
466: .getPingback().getIp(), null, null, permalink
467: .toString(), responseType,
468: pingbackMarkedSpamEvent.getPingback()
469: .getTitle(), pingbackMarkedSpamEvent
470: .getPingback().getBlogName(),
471: pingbackMarkedSpamEvent.getPingback().getUrl(),
472: pingbackMarkedSpamEvent.getPingback()
473: .getExcerpt(), null);
474: }
475: } else if (event instanceof PingbackUnmarkedSpamEvent) {
476: PingbackUnmarkedSpamEvent pingbackUnmarkedSpamEvent = (PingbackUnmarkedSpamEvent) event;
477: Blog blog = pingbackUnmarkedSpamEvent.getBlog();
478:
479: String akismetAPIKey = blog
480: .getProperty(AKISMET_PLUGIN_API_KEY_IP);
481: if (BlojsomUtils.checkNullOrBlank(akismetAPIKey)) {
482: if (_logger.isInfoEnabled()) {
483: _logger
484: .info("No Akismet API key provided for blog property: "
485: + AKISMET_PLUGIN_API_KEY_IP);
486: }
487: } else {
488: Akismet akismet = new Akismet(akismetAPIKey, blog
489: .getBlogURL());
490: String responseType = Akismet.COMMENT_TYPE_PINGBACK;
491: StringBuffer permalink = new StringBuffer();
492: permalink.append(blog.getBlogURL()).append("/").append(
493: pingbackUnmarkedSpamEvent.getEntry()
494: .getBlogCategory().getName()).append(
495: pingbackUnmarkedSpamEvent.getEntry()
496: .getPostSlug());
497:
498: akismet.submitHam(pingbackUnmarkedSpamEvent
499: .getPingback().getIp(), null, null, permalink
500: .toString(), responseType,
501: pingbackUnmarkedSpamEvent.getPingback()
502: .getTitle(), pingbackUnmarkedSpamEvent
503: .getPingback().getBlogName(),
504: pingbackUnmarkedSpamEvent.getPingback()
505: .getUrl(), pingbackUnmarkedSpamEvent
506: .getPingback().getExcerpt(), null);
507: }
508: }
509: }
510: }
|