aboutsummaryrefslogtreecommitdiff
path: root/subsonic-backend/src/main/java/net/sourceforge/subsonic/backend/controller/IPNController.java
diff options
context:
space:
mode:
Diffstat (limited to 'subsonic-backend/src/main/java/net/sourceforge/subsonic/backend/controller/IPNController.java')
-rw-r--r--subsonic-backend/src/main/java/net/sourceforge/subsonic/backend/controller/IPNController.java152
1 files changed, 152 insertions, 0 deletions
diff --git a/subsonic-backend/src/main/java/net/sourceforge/subsonic/backend/controller/IPNController.java b/subsonic-backend/src/main/java/net/sourceforge/subsonic/backend/controller/IPNController.java
new file mode 100644
index 00000000..f6ced54f
--- /dev/null
+++ b/subsonic-backend/src/main/java/net/sourceforge/subsonic/backend/controller/IPNController.java
@@ -0,0 +1,152 @@
+/*
+ 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 <http://www.gnu.org/licenses/>.
+
+ 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<String> 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;
+ }
+
+}