/* This file is part of Subsonic. Subsonic is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Subsonic is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Subsonic. If not, see . Copyright 2009 (C) Sindre Mehus */ package net.sourceforge.subsonic.backend.controller; import org.apache.log4j.Logger; import org.apache.http.client.HttpClient; import org.apache.http.client.ResponseHandler; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.impl.client.BasicResponseHandler; import org.apache.http.params.HttpConnectionParams; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.Controller; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.net.URLEncoder; import java.util.Enumeration; import java.util.Date; import java.io.UnsupportedEncodingException; import net.sourceforge.subsonic.backend.domain.Payment; import net.sourceforge.subsonic.backend.dao.PaymentDao; /** * Processes IPNs (Instant Payment Notifications) from PayPal. * * @author Sindre Mehus */ public class IPNController implements Controller { private static final Logger LOG = Logger.getLogger(IPNController.class); private static final String PAYPAL_URL = "https://www.paypal.com/cgi-bin/webscr"; private PaymentDao paymentDao; public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { try { LOG.info("Incoming IPN from " + request.getRemoteAddr()); String url = createValidationURL(request); if (validate(url)) { LOG.info("Verified payment. " + url); } else { LOG.warn("Failed to verify payment. " + url); } createOrUpdatePayment(request); return null; } catch (Exception x) { LOG.error("Failed to process IPN.", x); throw x; } } private String createValidationURL(HttpServletRequest request) throws UnsupportedEncodingException { Enumeration en = request.getParameterNames(); StringBuilder url = new StringBuilder(PAYPAL_URL).append("?cmd=_notify-validate"); String encoding = request.getParameter("charset"); if (encoding == null) { encoding = "ISO-8859-1"; } while (en.hasMoreElements()) { String paramName = (String) en.nextElement(); String paramValue = request.getParameter(paramName); url.append("&").append(paramName).append("=").append(URLEncoder.encode(paramValue, encoding)); } return url.toString(); } private void createOrUpdatePayment(HttpServletRequest request) { String item = request.getParameter("item_number"); if (item == null) { item = request.getParameter("item_number1"); } String paymentStatus = request.getParameter("payment_status"); String paymentType = request.getParameter("payment_type"); int paymentAmount = Math.round(new Float(request.getParameter("mc_gross"))); String paymentCurrency = request.getParameter("mc_currency"); String txnId = request.getParameter("txn_id"); String txnType = request.getParameter("txn_type"); String payerEmail = request.getParameter("payer_email"); String payerFirstName = request.getParameter("first_name"); String payerLastName = request.getParameter("last_name"); String payerCountry = request.getParameter("address_country"); Payment payment = paymentDao.getPaymentByTransactionId(txnId); if (payment == null) { payment = new Payment(null, txnId, txnType, item, paymentType, paymentStatus, paymentAmount, paymentCurrency, payerEmail, payerFirstName, payerLastName, payerCountry, Payment.ProcessingStatus.NEW, new Date(), new Date()); paymentDao.createPayment(payment); } else { payment.setTransactionType(txnType); payment.setItem(item); payment.setPaymentType(paymentType); payment.setPaymentStatus(paymentStatus); payment.setPaymentAmount(paymentAmount); payment.setPaymentCurrency(paymentCurrency); payment.setPayerEmail(payerEmail); payment.setPayerFirstName(payerFirstName); payment.setPayerLastName(payerLastName); payment.setPayerCountry(payerCountry); payment.setLastUpdated(new Date()); paymentDao.updatePayment(payment); } LOG.info("Received " + payment); } private boolean validate(String url) throws Exception { HttpClient client = new DefaultHttpClient(); HttpConnectionParams.setConnectionTimeout(client.getParams(), 60000); HttpConnectionParams.setSoTimeout(client.getParams(), 60000); HttpGet method = new HttpGet(url); String content; try { ResponseHandler responseHandler = new BasicResponseHandler(); content = client.execute(method, responseHandler); LOG.info("Validation result: " + content); return "VERIFIED".equals(content); } finally { client.getConnectionManager().shutdown(); } } public void setPaymentDao(PaymentDao paymentDao) { this.paymentDao = paymentDao; } }