diff options
-rw-r--r-- | README | 2 | ||||
-rw-r--r-- | configure.ac | 35 | ||||
-rw-r--r-- | src/backend/Makefile.am | 21 | ||||
-rw-r--r-- | src/backend/taler-merchant-httpd_get-orders-ID.c | 237 |
4 files changed, 257 insertions, 38 deletions
@@ -27,7 +27,7 @@ libgcrypt: LGPL, owned by Free Software Foundation postgresql: PostgreSQL License, AGPL- and LGPL-Compatible, owned by The PostgreSQL Global Development Group libgnunetutil (in all of its variants): GPLv3+, owned by GNUnet e.V. -PHP: PHP License, AGPL- and LGPL-Compatible, owned by The PHP Group +libqrencode: LGPL v2.1+, Copyright Kentaro Fukuchi 5. DIRECTORY STRUCTURE diff --git a/configure.ac b/configure.ac index 0f5a5fb8..399f7592 100644 --- a/configure.ac +++ b/configure.ac @@ -132,6 +132,41 @@ PKG_CHECK_MODULES([JANSSON], [jansson >= 2.3], *** You need libjansson to build this program. ***]])]) + +# test for libqrencode +qrencode=0 +QR_LIBS="-lqrencode" +AC_MSG_CHECKING(for libqrencode) +AC_ARG_WITH(qrencode, + [ --with-qrencode=PFX Base of libqrencode installation], + [AC_MSG_RESULT([$with_qrencode]) + AS_CASE([$with_qrencode], + [no],[], + [yes],[ + AC_CHECK_HEADERS(qrencode.h,qrencode=1) + ], + [ + CPPFLAGS="-I$with_qrencode/include $CPPFLAGS" + QR_CFLAGS="-I$with_qrencode/include" + QR_LIBS="-L$with_qrencode/lib -lqrencode" + AC_CHECK_HEADERS(qrencode.h,qrencode=1) + ]) + ], + [AC_MSG_RESULT([--with-qrencode not specified]) + AC_CHECK_HEADERS(qrencode.h,qrencode=1)]) + +AS_IF([test "$qrencode" != 1], +[AC_MSG_ERROR([[ +*** +*** You need libqrencode to build this program. +*** ]])]) + + +AC_SUBST(QR_CFLAGS) +AC_SUBST(QR_LIBS) + + + # check for libgnurl # libgnurl LIBGNURL_CHECK_CONFIG(,7.34.0,gnurl=1,gnurl=0) diff --git a/src/backend/Makefile.am b/src/backend/Makefile.am index 87bd5efe..a95026fb 100644 --- a/src/backend/Makefile.am +++ b/src/backend/Makefile.am @@ -91,24 +91,6 @@ taler_merchant_httpd_SOURCES = \ taler-merchant-httpd_post-tips-ID-pickup.h \ taler-merchant-httpd_reserves.c \ taler-merchant-httpd_reserves.h - -DEAD = \ - taler-merchant-httpd_check-payment.c taler-merchant-httpd_check-payment.h \ - taler-merchant-httpd_history.c taler-merchant-httpd_history.h \ - taler-merchant-httpd_order.c taler-merchant-httpd_order.h \ - taler-merchant-httpd_pay.c taler-merchant-httpd_pay.h \ - taler-merchant-httpd_poll-payment.c taler-merchant-httpd_poll-payment.h \ - taler-merchant-httpd_proposal.c taler-merchant-httpd_proposal.h \ - taler-merchant-httpd_refund.c taler-merchant-httpd_refund.h \ - taler-merchant-httpd_refund_increase.c taler-merchant-httpd_refund_increase.h \ - taler-merchant-httpd_refund_lookup.c taler-merchant-httpd_refund_lookup.h \ - taler-merchant-httpd_tip-authorize.c taler-merchant-httpd_tip-authorize.h \ - taler-merchant-httpd_tip-pickup.c taler-merchant-httpd_tip-pickup.h \ - taler-merchant-httpd_tip-pickup_get.c \ - taler-merchant-httpd_tip-query.c taler-merchant-httpd_tip-query.h \ - taler-merchant-httpd_tip-reserve-helper.c taler-merchant-httpd_tip-reserve-helper.h \ - taler-merchant-httpd_track-transaction.c taler-merchant-httpd_track-transaction.h \ - taler-merchant-httpd_track-transfer.c taler-merchant-httpd_track-transfer.h taler_merchant_httpd_LDADD = \ $(top_builddir)/src/backenddb/libtalermerchantdb.la \ -ltalerexchange \ @@ -122,4 +104,7 @@ taler_merchant_httpd_LDADD = \ -lgnunetcurl \ -lgnunetjson \ -lgnunetutil \ + @QR_LIBS@ $(XLIB) +taler_merchant_httpd_CFLAGS = \ + @QR_CFLAGS@ diff --git a/src/backend/taler-merchant-httpd_get-orders-ID.c b/src/backend/taler-merchant-httpd_get-orders-ID.c index 21582699..7310483d 100644 --- a/src/backend/taler-merchant-httpd_get-orders-ID.c +++ b/src/backend/taler-merchant-httpd_get-orders-ID.c @@ -21,6 +21,7 @@ */ #include "platform.h" #include <jansson.h> +#include <qrencode.h> #include <taler/taler_signatures.h> #include <taler/taler_json_lib.h> #include <taler/taler_exchange_service.h> @@ -220,6 +221,12 @@ struct GetOrderData */ bool refunded; + /** + * Set to true if the client requested HTML, otherwise + * we generate JSON. + */ + bool generate_html; + }; @@ -235,6 +242,77 @@ static struct GetOrderData *god_tail; /** + * Create the QR code image for a URI. + * + * @param uri input string to encode + * @return NULL on error, encoded URI otherwise + */ +static char * +create_qrcode (const char *uri) +{ + QRinput *qri; + QRcode *qrc; + struct GNUNET_Buffer buf = { 0 }; + + qri = QRinput_new2 (0, + QR_ECLEVEL_M); + if (NULL == qri) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, + "QRinput_new2"); + return NULL; + } + /* first try encoding as uppercase-only alpha-numerical + QR code (much smaller encoding); if that fails, also + try using binary encoding */ + if ( (0 != + QRinput_append (qri, + QR_MODE_AN, + strlen (uri), + (unsigned char *) uri)) && + (0 != + QRinput_append (qri, + QR_MODE_8, + strlen (uri), + (unsigned char *) uri)) ) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, + "QRinput_append"); + QRinput_free (qri); + return NULL; + } + qrc = QRcode_encodeInput (qri); + if (NULL == qrc) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, + "QRcode_encodeInput"); + QRinput_free (qri); + return NULL; + } + QRinput_free (qri); + /* FIXME-Dold: generate <img> with inline SVG instead of <pre> here! */ + GNUNET_buffer_write_str (&buf, + "<pre>\n\n\n\n "); + for (unsigned int y = 0; y<qrc->width; y++) + { + for (unsigned int x = 0; x<qrc->width; x++) + { + unsigned int off = x + y * qrc->width; + GNUNET_buffer_write_fstr (&buf, + "%s", + (0 != (qrc->data[off] & 1)) ? "██" : " "); + } + GNUNET_buffer_write_str (&buf, + "\n "); + } + GNUNET_buffer_write_str (&buf, + "\n\n\n\n</pre>"); + QRcode_free (qrc); + return GNUNET_buffer_reap_str (&buf); +} + + +/** * Force resuming all suspended order lookups, needed during shutdown. */ void @@ -375,13 +453,54 @@ send_pay_request (struct GetOrderData *god, god->order_id, god->session_id, god->hc->instance->settings.id); - ret = TALER_MHD_reply_json_pack (god->sc.con, - MHD_HTTP_OK, - "{s:s, s:s, s:s?}", - "taler_pay_uri", taler_pay_uri, - "order_status", "unpaid", - "already_paid_order_id", - already_paid_order_id); + if (god->generate_html) + { + struct MHD_Response *reply; + char *qr; + char *body; + + qr = create_qrcode (taler_pay_uri); + if (NULL == qr) + { + GNUNET_break (0); + return MHD_NO; + } + GNUNET_asprintf (&body, + "<html><body>%s</body></html>", + qr); + GNUNET_free (qr); + reply = MHD_create_response_from_buffer (strlen (body), + body, + MHD_RESPMEM_MUST_COPY); + GNUNET_free (body); + if (NULL == reply) + { + GNUNET_break (0); + return MHD_NO; + } + GNUNET_break (MHD_NO != + MHD_add_response_header (reply, + "Taler", + taler_pay_uri)); + GNUNET_break (MHD_NO != + MHD_add_response_header (reply, + MHD_HTTP_HEADER_CONTENT_TYPE, + "text/html")); + ret = MHD_queue_response (god->sc.con, + MHD_HTTP_OK, + reply); + MHD_destroy_response (reply); + } + else + { + ret = TALER_MHD_reply_json_pack (god->sc.con, + MHD_HTTP_OK, + "{s:s, s:s, s:s?}", + "taler_pay_uri", taler_pay_uri, + "order_status", "unpaid", + "already_paid_order_id", + already_paid_order_id); + } GNUNET_free (taler_pay_uri); return ret; } @@ -683,6 +802,44 @@ TMH_get_orders_ID (const struct TMH_RequestHandler *rh, } } + { /* check for 'Accept' header */ + const char *accept; + + accept = MHD_lookup_connection_value (connection, + MHD_HEADER_KIND, + MHD_HTTP_HEADER_ACCEPT); + if (NULL != accept) + { + char *a = GNUNET_strdup (accept); + char *saveptr; + + for (char *t = strtok_r (a, ",", &saveptr); + NULL != t; + t = strtok_r (NULL, ",", &saveptr)) + { + char *end; + + /* skip leading whitespace */ + while (isspace ((unsigned char) t[0])) + t++; + /* trim of ';q=' parameter and everything after space */ + end = strchr (t, ';'); + if (NULL != end) + *end = '\0'; + end = strchr (t, ' '); + if (NULL != end) + *end = '\0'; + if (0 == strcasecmp ("text/html", + t)) + { + god->generate_html = true; + break; + } + } + GNUNET_free (a); + } + } /* end check for 'Accept' header */ + { const char *long_poll_timeout_s; @@ -1058,18 +1215,60 @@ TMH_get_orders_ID (const struct TMH_RequestHandler *rh, refund)); } - return TALER_MHD_reply_json_pack ( - connection, - MHD_HTTP_OK, - "{s:s, s:b, s:o, s:o, s:o}", - "order_status", "paid", - "refunded", god->refunded, - "refund_amount", - TALER_JSON_from_amount (&god->refund_amount), - "refunds", - ra, - "merchant_pub", - GNUNET_JSON_from_data_auto (&hc->instance->merchant_pub)); + if (god->generate_html) + { + int ret; + struct MHD_Response *reply; + char *body; + +#if 0 + char *qr; + + qr = create_qrcode (taler_refund_uri); + if (NULL == qr) + { + GNUNET_break (0); + return MHD_NO; + } +#endif + GNUNET_asprintf (&body, + "<html><body>Paid. Refund: %s</body></html>", + TALER_amount2s (&god->refund_amount)); + // GNUNET_free (qr); + reply = MHD_create_response_from_buffer (strlen (body), + body, + MHD_RESPMEM_MUST_COPY); + GNUNET_free (body); + if (NULL == reply) + { + GNUNET_break (0); + return MHD_NO; + } + GNUNET_break (MHD_NO != + MHD_add_response_header (reply, + MHD_HTTP_HEADER_CONTENT_TYPE, + "text/html")); + ret = MHD_queue_response (god->sc.con, + MHD_HTTP_OK, + reply); + MHD_destroy_response (reply); + return ret; + } + else + { + return TALER_MHD_reply_json_pack ( + connection, + MHD_HTTP_OK, + "{s:s, s:b, s:o, s:o, s:o}", + "order_status", "paid", + "refunded", god->refunded, + "refund_amount", + TALER_JSON_from_amount (&god->refund_amount), + "refunds", + ra, + "merchant_pub", + GNUNET_JSON_from_data_auto (&hc->instance->merchant_pub)); + } } } |