diff options
Diffstat (limited to 'src/merchant')
-rw-r--r-- | src/merchant/.gitignore | 1 | ||||
-rw-r--r-- | src/merchant/Makefile | 731 | ||||
-rw-r--r-- | src/merchant/Makefile.am | 52 | ||||
-rw-r--r-- | src/merchant/Makefile.in | 731 | ||||
-rw-r--r-- | src/merchant/merchant.c | 173 | ||||
-rw-r--r-- | src/merchant/merchant.h | 110 | ||||
-rw-r--r-- | src/merchant/merchant_db.c | 347 | ||||
-rw-r--r-- | src/merchant/merchant_db.h | 98 | ||||
-rw-r--r-- | src/merchant/taler_merchant_dbinit.c | 79 | ||||
-rw-r--r-- | src/merchant/taler_merchant_serve.c | 1559 | ||||
-rw-r--r-- | src/merchant/test_merchant.c | 96 | ||||
-rw-r--r-- | src/merchant/test_merchant.conf | 36 | ||||
-rw-r--r-- | src/merchant/test_merchant.ecc | 2 | ||||
-rw-r--r-- | src/merchant/test_merchant_db.c | 147 |
14 files changed, 4162 insertions, 0 deletions
diff --git a/src/merchant/.gitignore b/src/merchant/.gitignore new file mode 100644 index 00000000..ebe41680 --- /dev/null +++ b/src/merchant/.gitignore @@ -0,0 +1 @@ +taler-merchant-* diff --git a/src/merchant/Makefile b/src/merchant/Makefile new file mode 100644 index 00000000..bbc16e7b --- /dev/null +++ b/src/merchant/Makefile @@ -0,0 +1,731 @@ +# Makefile.in generated by automake 1.14.1 from Makefile.am. +# src/merchant/Makefile. Generated from Makefile.in by configure. + +# Copyright (C) 1994-2013 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + + + +am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/taler +pkgincludedir = $(includedir)/taler +pkglibdir = $(libdir)/taler +pkglibexecdir = $(libexecdir)/taler +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = x86_64-unknown-linux-gnu +host_triplet = x86_64-unknown-linux-gnu +bin_PROGRAMS = taler-merchant-dbinit$(EXEEXT) \ + taler-merchant-serve$(EXEEXT) +check_PROGRAMS = test-merchant$(EXEEXT) test-merchant-db$(EXEEXT) +subdir = src/merchant +DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ + $(top_srcdir)/depcomp +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_postgresql.m4 \ + $(top_srcdir)/m4/libgnurl.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/taler_config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__installdirs = "$(DESTDIR)$(bindir)" +PROGRAMS = $(bin_PROGRAMS) +am__objects_1 = merchant_db.$(OBJEXT) +am_taler_merchant_dbinit_OBJECTS = taler_merchant_dbinit.$(OBJEXT) \ + $(am__objects_1) +taler_merchant_dbinit_OBJECTS = $(am_taler_merchant_dbinit_OBJECTS) +taler_merchant_dbinit_DEPENDENCIES = +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +am__v_lt_1 = +taler_merchant_dbinit_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(taler_merchant_dbinit_LDFLAGS) \ + $(LDFLAGS) -o $@ +am_taler_merchant_serve_OBJECTS = taler_merchant_serve.$(OBJEXT) \ + merchant.$(OBJEXT) $(am__objects_1) +taler_merchant_serve_OBJECTS = $(am_taler_merchant_serve_OBJECTS) +taler_merchant_serve_DEPENDENCIES = +taler_merchant_serve_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(taler_merchant_serve_LDFLAGS) \ + $(LDFLAGS) -o $@ +am_test_merchant_OBJECTS = merchant.$(OBJEXT) test_merchant.$(OBJEXT) +test_merchant_OBJECTS = $(am_test_merchant_OBJECTS) +test_merchant_DEPENDENCIES = +am_test_merchant_db_OBJECTS = $(am__objects_1) \ + test_merchant_db.$(OBJEXT) +test_merchant_db_OBJECTS = $(am_test_merchant_db_OBJECTS) +test_merchant_db_DEPENDENCIES = +AM_V_P = $(am__v_P_$(V)) +am__v_P_ = $(am__v_P_$(AM_DEFAULT_VERBOSITY)) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I. -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = +SOURCES = $(taler_merchant_dbinit_SOURCES) \ + $(taler_merchant_serve_SOURCES) $(test_merchant_SOURCES) \ + $(test_merchant_db_SOURCES) +DIST_SOURCES = $(taler_merchant_dbinit_SOURCES) \ + $(taler_merchant_serve_SOURCES) $(test_merchant_SOURCES) \ + $(test_merchant_db_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = ${SHELL} /home/grothoff/research/merchant/missing aclocal-1.14 +AMTAR = $${TAR-tar} +AM_DEFAULT_VERBOSITY = 0 +AR = ar +AUTOCONF = ${SHELL} /home/grothoff/research/merchant/missing autoconf +AUTOHEADER = ${SHELL} /home/grothoff/research/merchant/missing autoheader +AUTOMAKE = ${SHELL} /home/grothoff/research/merchant/missing automake-1.14 +AWK = gawk +CC = gcc +CCDEPMODE = depmode=gcc3 +CFLAGS = -Wall -g -O0 -Wall +CPP = gcc -E +CPPFLAGS = -I/home/grothoff//include +CYGPATH_W = echo +DEFS = -DHAVE_CONFIG_H +DEPDIR = .deps +DLLTOOL = false +DSYMUTIL = +DUMPBIN = +ECHO_C = +ECHO_N = -n +ECHO_T = +EGREP = /bin/grep -E +EXEEXT = +FGREP = /bin/grep -F +GREP = /bin/grep +INSTALL = /usr/bin/install -c +INSTALL_DATA = ${INSTALL} -m 644 +INSTALL_PROGRAM = ${INSTALL} +INSTALL_SCRIPT = ${INSTALL} +INSTALL_STRIP_PROGRAM = $(install_sh) -c -s +LD = /usr/bin/ld -m elf_x86_64 +LDFLAGS = -L/home/grothoff//lib +LIBGCRYPT_CFLAGS = +LIBGCRYPT_CONFIG = /usr/bin/libgcrypt-config +LIBGCRYPT_LIBS = -lgcrypt +LIBGNURL = -L/home/grothoff/lib -lgnurl +LIBGNURL_CPPFLAGS = -I/home/grothoff/include +LIBOBJS = +LIBS = +LIBTOOL = $(SHELL) $(top_builddir)/libtool +LIPO = +LN_S = ln -s +LTLIBOBJS = +MAKEINFO = ${SHELL} /home/grothoff/research/merchant/missing makeinfo +MANIFEST_TOOL = : +MKDIR_P = /bin/mkdir -p +NM = /usr/bin/nm -B +NMEDIT = +OBJDUMP = objdump +OBJEXT = o +OTOOL = +OTOOL64 = +PACKAGE = taler +PACKAGE_BUGREPORT = taler-bug@gnunet.org +PACKAGE_NAME = taler +PACKAGE_STRING = taler 0.0.0 +PACKAGE_TARNAME = taler +PACKAGE_URL = +PACKAGE_VERSION = 0.0.0 +PATH_SEPARATOR = : +PG_CONFIG = /usr/bin/pg_config +POSTGRESQL_CPPFLAGS = -I/usr/include/postgresql +POSTGRESQL_LDFLAGS = -L/usr/lib/x86_64-linux-gnu +POSTGRESQL_VERSION = 9.4.0 +RANLIB = ranlib +SED = /bin/sed +SET_MAKE = +SHELL = /bin/bash +STRIP = strip +VERSION = 0.0.0 +_libgnurl_config = +abs_builddir = /home/grothoff/research/merchant/src/merchant +abs_srcdir = /home/grothoff/research/merchant/src/merchant +abs_top_builddir = /home/grothoff/research/merchant +abs_top_srcdir = /home/grothoff/research/merchant +ac_ct_AR = ar +ac_ct_CC = gcc +ac_ct_DUMPBIN = +am__include = include +am__leading_dot = . +am__quote = +am__tar = $${TAR-tar} chof - "$$tardir" +am__untar = $${TAR-tar} xf - +bindir = ${exec_prefix}/bin +build = x86_64-unknown-linux-gnu +build_alias = +build_cpu = x86_64 +build_os = linux-gnu +build_vendor = unknown +builddir = . +datadir = ${datarootdir} +datarootdir = ${prefix}/share +docdir = ${datarootdir}/doc/${PACKAGE_TARNAME} +dvidir = ${docdir} +exec_prefix = ${prefix} +host = x86_64-unknown-linux-gnu +host_alias = +host_cpu = x86_64 +host_os = linux-gnu +host_vendor = unknown +htmldir = ${docdir} +includedir = ${prefix}/include +infodir = ${datarootdir}/info +install_sh = ${SHELL} /home/grothoff/research/merchant/install-sh +libdir = ${exec_prefix}/lib +libexecdir = ${exec_prefix}/libexec +localedir = ${datarootdir}/locale +localstatedir = ${prefix}/var +mandir = ${datarootdir}/man +mkdir_p = $(MKDIR_P) +oldincludedir = /usr/include +pdfdir = ${docdir} +prefix = /usr/local +program_transform_name = s,x,x, +psdir = ${docdir} +sbindir = ${exec_prefix}/sbin +sharedstatedir = ${prefix}/com +srcdir = . +sysconfdir = ${prefix}/etc +target_alias = +top_build_prefix = ../../ +top_builddir = ../.. +top_srcdir = ../.. +AM_CPPFLAGS = -I$(top_srcdir)/src/include $(POSTGRESQL_CPPFLAGS) +MERCHANT_DB = merchant_db.c merchant_db.h +taler_merchant_dbinit_SOURCES = \ + taler_merchant_dbinit.c \ + $(MERCHANT_DB) + +taler_merchant_dbinit_LDADD = \ + -lpq \ + -lgnunetutil \ + -ltalerutil \ + -lgnunetpostgres + +taler_merchant_dbinit_LDFLAGS = \ + $(POSTGRESQL_LDFLAGS) + +test_merchant_SOURCES = \ + merchant.c \ + test_merchant.c + +test_merchant_LDADD = \ + -ltalerutil \ + -lgnunetutil + +test_merchant_db_SOURCES = \ + $(MERCHANT_DB) \ + test_merchant_db.c + +test_merchant_db_LDADD = \ + -ltalerutil \ + -lgnunetutil \ + -lgnunetpostgres \ + -lpq + +taler_merchant_serve_SOURCES = \ + taler_merchant_serve.c \ + merchant.c merchant.h \ + $(MERCHANT_DB) + +taler_merchant_serve_LDADD = \ + -lpq \ + -lgnunetutil \ + -lgnunetpostgres \ + -lmicrohttpd \ + -ltalermintapi \ + -ltalerutil \ + -ljansson + +taler_merchant_serve_LDFLAGS = \ + $(POSTGRESQL_LDFLAGS) + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/merchant/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/merchant/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ + fi; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p \ + || test -f $$p1 \ + ; then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' \ + -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' \ + `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(bindir)" && rm -f $$files + +clean-binPROGRAMS: + @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list + +clean-checkPROGRAMS: + @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list + +taler-merchant-dbinit$(EXEEXT): $(taler_merchant_dbinit_OBJECTS) $(taler_merchant_dbinit_DEPENDENCIES) $(EXTRA_taler_merchant_dbinit_DEPENDENCIES) + @rm -f taler-merchant-dbinit$(EXEEXT) + $(AM_V_CCLD)$(taler_merchant_dbinit_LINK) $(taler_merchant_dbinit_OBJECTS) $(taler_merchant_dbinit_LDADD) $(LIBS) + +taler-merchant-serve$(EXEEXT): $(taler_merchant_serve_OBJECTS) $(taler_merchant_serve_DEPENDENCIES) $(EXTRA_taler_merchant_serve_DEPENDENCIES) + @rm -f taler-merchant-serve$(EXEEXT) + $(AM_V_CCLD)$(taler_merchant_serve_LINK) $(taler_merchant_serve_OBJECTS) $(taler_merchant_serve_LDADD) $(LIBS) + +test-merchant$(EXEEXT): $(test_merchant_OBJECTS) $(test_merchant_DEPENDENCIES) $(EXTRA_test_merchant_DEPENDENCIES) + @rm -f test-merchant$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_merchant_OBJECTS) $(test_merchant_LDADD) $(LIBS) + +test-merchant-db$(EXEEXT): $(test_merchant_db_OBJECTS) $(test_merchant_db_DEPENDENCIES) $(EXTRA_test_merchant_db_DEPENDENCIES) + @rm -f test-merchant-db$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_merchant_db_OBJECTS) $(test_merchant_db_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +include ./$(DEPDIR)/merchant.Po +include ./$(DEPDIR)/merchant_db.Po +include ./$(DEPDIR)/taler_merchant_dbinit.Po +include ./$(DEPDIR)/taler_merchant_serve.Po +include ./$(DEPDIR)/test_merchant.Po +include ./$(DEPDIR)/test_merchant_db.Po + +.c.o: + $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ + $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ + $(am__mv) $$depbase.Tpo $$depbase.Po +# $(AM_V_CC)source='$<' object='$@' libtool=no \ +# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \ +# $(AM_V_CC_no)$(COMPILE) -c -o $@ $< + +.c.obj: + $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ + $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ + $(am__mv) $$depbase.Tpo $$depbase.Po +# $(AM_V_CC)source='$<' object='$@' libtool=no \ +# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \ +# $(AM_V_CC_no)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.c.lo: + $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ + $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ + $(am__mv) $$depbase.Tpo $$depbase.Plo +# $(AM_V_CC)source='$<' object='$@' libtool=yes \ +# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \ +# $(AM_V_CC_no)$(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) +check: check-am +all-am: Makefile $(PROGRAMS) +installdirs: + for dir in "$(DESTDIR)$(bindir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ + clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-binPROGRAMS + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS + +.MAKE: check-am install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean \ + clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ + clean-libtool cscopelist-am ctags ctags-am distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-binPROGRAMS install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags tags-am uninstall uninstall-am uninstall-binPROGRAMS + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/merchant/Makefile.am b/src/merchant/Makefile.am new file mode 100644 index 00000000..701b3ee8 --- /dev/null +++ b/src/merchant/Makefile.am @@ -0,0 +1,52 @@ +AM_CPPFLAGS = -I$(top_srcdir)/src/include $(POSTGRESQL_CPPFLAGS) + +MERCHANT_DB = merchant_db.c merchant_db.h +bin_PROGRAMS = \ + taler-merchant-dbinit \ + taler-merchant-serve + +taler_merchant_dbinit_SOURCES = \ + taler_merchant_dbinit.c \ + $(MERCHANT_DB) +taler_merchant_dbinit_LDADD = \ + -lpq \ + -lgnunetutil \ + -ltalerutil \ + -lgnunetpostgres +taler_merchant_dbinit_LDFLAGS = \ + $(POSTGRESQL_LDFLAGS) + +check_PROGRAMS = \ + test-merchant \ + test-merchant-db + +test_merchant_SOURCES = \ + merchant.c \ + test_merchant.c +test_merchant_LDADD = \ + -ltalerutil \ + -lgnunetutil + +test_merchant_db_SOURCES = \ + $(MERCHANT_DB) \ + test_merchant_db.c +test_merchant_db_LDADD = \ + -ltalerutil \ + -lgnunetutil \ + -lgnunetpostgres \ + -lpq + +taler_merchant_serve_SOURCES = \ + taler_merchant_serve.c \ + merchant.c merchant.h \ + $(MERCHANT_DB) +taler_merchant_serve_LDADD = \ + -lpq \ + -lgnunetutil \ + -lgnunetpostgres \ + -lmicrohttpd \ + -ltalermintapi \ + -ltalerutil \ + -ljansson +taler_merchant_serve_LDFLAGS = \ + $(POSTGRESQL_LDFLAGS) diff --git a/src/merchant/Makefile.in b/src/merchant/Makefile.in new file mode 100644 index 00000000..33fcb832 --- /dev/null +++ b/src/merchant/Makefile.in @@ -0,0 +1,731 @@ +# Makefile.in generated by automake 1.14.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2013 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +bin_PROGRAMS = taler-merchant-dbinit$(EXEEXT) \ + taler-merchant-serve$(EXEEXT) +check_PROGRAMS = test-merchant$(EXEEXT) test-merchant-db$(EXEEXT) +subdir = src/merchant +DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ + $(top_srcdir)/depcomp +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_postgresql.m4 \ + $(top_srcdir)/m4/libgnurl.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/taler_config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__installdirs = "$(DESTDIR)$(bindir)" +PROGRAMS = $(bin_PROGRAMS) +am__objects_1 = merchant_db.$(OBJEXT) +am_taler_merchant_dbinit_OBJECTS = taler_merchant_dbinit.$(OBJEXT) \ + $(am__objects_1) +taler_merchant_dbinit_OBJECTS = $(am_taler_merchant_dbinit_OBJECTS) +taler_merchant_dbinit_DEPENDENCIES = +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +taler_merchant_dbinit_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(taler_merchant_dbinit_LDFLAGS) \ + $(LDFLAGS) -o $@ +am_taler_merchant_serve_OBJECTS = taler_merchant_serve.$(OBJEXT) \ + merchant.$(OBJEXT) $(am__objects_1) +taler_merchant_serve_OBJECTS = $(am_taler_merchant_serve_OBJECTS) +taler_merchant_serve_DEPENDENCIES = +taler_merchant_serve_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(taler_merchant_serve_LDFLAGS) \ + $(LDFLAGS) -o $@ +am_test_merchant_OBJECTS = merchant.$(OBJEXT) test_merchant.$(OBJEXT) +test_merchant_OBJECTS = $(am_test_merchant_OBJECTS) +test_merchant_DEPENDENCIES = +am_test_merchant_db_OBJECTS = $(am__objects_1) \ + test_merchant_db.$(OBJEXT) +test_merchant_db_OBJECTS = $(am_test_merchant_db_OBJECTS) +test_merchant_db_DEPENDENCIES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = +SOURCES = $(taler_merchant_dbinit_SOURCES) \ + $(taler_merchant_serve_SOURCES) $(test_merchant_SOURCES) \ + $(test_merchant_db_SOURCES) +DIST_SOURCES = $(taler_merchant_dbinit_SOURCES) \ + $(taler_merchant_serve_SOURCES) $(test_merchant_SOURCES) \ + $(test_merchant_db_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ +LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ +LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ +LIBGNURL = @LIBGNURL@ +LIBGNURL_CPPFLAGS = @LIBGNURL_CPPFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PG_CONFIG = @PG_CONFIG@ +POSTGRESQL_CPPFLAGS = @POSTGRESQL_CPPFLAGS@ +POSTGRESQL_LDFLAGS = @POSTGRESQL_LDFLAGS@ +POSTGRESQL_VERSION = @POSTGRESQL_VERSION@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +_libgnurl_config = @_libgnurl_config@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +AM_CPPFLAGS = -I$(top_srcdir)/src/include $(POSTGRESQL_CPPFLAGS) +MERCHANT_DB = merchant_db.c merchant_db.h +taler_merchant_dbinit_SOURCES = \ + taler_merchant_dbinit.c \ + $(MERCHANT_DB) + +taler_merchant_dbinit_LDADD = \ + -lpq \ + -lgnunetutil \ + -ltalerutil \ + -lgnunetpostgres + +taler_merchant_dbinit_LDFLAGS = \ + $(POSTGRESQL_LDFLAGS) + +test_merchant_SOURCES = \ + merchant.c \ + test_merchant.c + +test_merchant_LDADD = \ + -ltalerutil \ + -lgnunetutil + +test_merchant_db_SOURCES = \ + $(MERCHANT_DB) \ + test_merchant_db.c + +test_merchant_db_LDADD = \ + -ltalerutil \ + -lgnunetutil \ + -lgnunetpostgres \ + -lpq + +taler_merchant_serve_SOURCES = \ + taler_merchant_serve.c \ + merchant.c merchant.h \ + $(MERCHANT_DB) + +taler_merchant_serve_LDADD = \ + -lpq \ + -lgnunetutil \ + -lgnunetpostgres \ + -lmicrohttpd \ + -ltalermintapi \ + -ltalerutil \ + -ljansson + +taler_merchant_serve_LDFLAGS = \ + $(POSTGRESQL_LDFLAGS) + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/merchant/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/merchant/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ + fi; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p \ + || test -f $$p1 \ + ; then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' \ + -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' \ + `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(bindir)" && rm -f $$files + +clean-binPROGRAMS: + @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list + +clean-checkPROGRAMS: + @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list + +taler-merchant-dbinit$(EXEEXT): $(taler_merchant_dbinit_OBJECTS) $(taler_merchant_dbinit_DEPENDENCIES) $(EXTRA_taler_merchant_dbinit_DEPENDENCIES) + @rm -f taler-merchant-dbinit$(EXEEXT) + $(AM_V_CCLD)$(taler_merchant_dbinit_LINK) $(taler_merchant_dbinit_OBJECTS) $(taler_merchant_dbinit_LDADD) $(LIBS) + +taler-merchant-serve$(EXEEXT): $(taler_merchant_serve_OBJECTS) $(taler_merchant_serve_DEPENDENCIES) $(EXTRA_taler_merchant_serve_DEPENDENCIES) + @rm -f taler-merchant-serve$(EXEEXT) + $(AM_V_CCLD)$(taler_merchant_serve_LINK) $(taler_merchant_serve_OBJECTS) $(taler_merchant_serve_LDADD) $(LIBS) + +test-merchant$(EXEEXT): $(test_merchant_OBJECTS) $(test_merchant_DEPENDENCIES) $(EXTRA_test_merchant_DEPENDENCIES) + @rm -f test-merchant$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_merchant_OBJECTS) $(test_merchant_LDADD) $(LIBS) + +test-merchant-db$(EXEEXT): $(test_merchant_db_OBJECTS) $(test_merchant_db_DEPENDENCIES) $(EXTRA_test_merchant_db_DEPENDENCIES) + @rm -f test-merchant-db$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_merchant_db_OBJECTS) $(test_merchant_db_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/merchant.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/merchant_db.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/taler_merchant_dbinit.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/taler_merchant_serve.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_merchant.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_merchant_db.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ +@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) +check: check-am +all-am: Makefile $(PROGRAMS) +installdirs: + for dir in "$(DESTDIR)$(bindir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ + clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-binPROGRAMS + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS + +.MAKE: check-am install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean \ + clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ + clean-libtool cscopelist-am ctags ctags-am distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-binPROGRAMS install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags tags-am uninstall uninstall-am uninstall-binPROGRAMS + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/merchant/merchant.c b/src/merchant/merchant.c new file mode 100644 index 00000000..f124a030 --- /dev/null +++ b/src/merchant/merchant.c @@ -0,0 +1,173 @@ +/* + This file is part of TALER + (C) 2014 Christian Grothoff (and other contributing authors) + + TALER 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, or (at your option) any later version. + + TALER 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 + TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> +*/ + +/** + * @file merchant/merchant.c + * @brief Common utility functions for merchant + * @author Sree Harsha Totakura <sreeharsha@totakura.in> + */ + +#include "platform.h" +#include <gnunet/gnunet_util_lib.h> +#include "merchant.h" + + +#define EXITIF(cond) \ + do { \ + if (cond) { GNUNET_break (0); goto EXITIF_exit; } \ + } while (0) + + +/** + * Parses mints from the configuration. + * + * @param cfg the configuration + * @param mints the array of mints upon successful parsing. Will be NULL upon + * error. + * @return the number of mints in the above array; GNUNET_SYSERR upon error in + * parsing. + */ +int +TALER_MERCHANT_parse_mints (const struct GNUNET_CONFIGURATION_Handle *cfg, + struct MERCHANT_MintInfo **mints) +{ + char *mints_str; + char *token_nf; /* do no free (nf) */ + char *mint_section; + char *mint_hostname; + char *mint_pubkey_enc; + struct MERCHANT_MintInfo *r_mints; + struct MERCHANT_MintInfo mint; + unsigned long long mint_port; + unsigned int cnt; + int OK; + + OK = 0; + mints_str = NULL; + token_nf = NULL; + mint_section = NULL; + mint_hostname = NULL; + mint_pubkey_enc = NULL; + r_mints = NULL; + cnt = 0; + EXITIF (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, + "merchant", + "TRUSTED_MINTS", + &mints_str)); + for (token_nf = strtok (mints_str, " "); + NULL != token_nf; + token_nf = strtok (NULL, " ")) + { + GNUNET_assert (0 < GNUNET_asprintf (&mint_section, + "mint-%s", token_nf)); + EXITIF (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, + mint_section, + "HOSTNAME", + &mint_hostname)); + EXITIF (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (cfg, + mint_section, + "PORT", + &mint_port)); + EXITIF (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, + mint_section, + "PUBKEY", + &mint_pubkey_enc)); + EXITIF (GNUNET_OK != + GNUNET_CRYPTO_eddsa_public_key_from_string (mint_pubkey_enc, + strlen (mint_pubkey_enc), + &mint.pubkey)); + mint.hostname = mint_hostname; + mint.port = (uint16_t) mint_port; + GNUNET_array_append (r_mints, cnt, mint); + mint_hostname = NULL; + GNUNET_free (mint_pubkey_enc); + mint_pubkey_enc = NULL; + GNUNET_free (mint_section); + mint_section = NULL; + } + OK = 1; + + EXITIF_exit: + GNUNET_free_non_null (mints_str); + GNUNET_free_non_null (mint_section); + GNUNET_free_non_null (mint_hostname); + GNUNET_free_non_null (mint_pubkey_enc); + if (!OK) + { + GNUNET_free_non_null (r_mints); + return GNUNET_SYSERR; + } + + *mints = r_mints; + return cnt; +} + + +/** + * Parse the SEPA information from the configuration. If any of the required + * fileds is missing return NULL. + * + * @param cfg the configuration + * @return Sepa details as a structure; NULL upon error + */ +struct MERCHANT_WIREFORMAT_Sepa * +TALER_MERCHANT_parse_wireformat_sepa (const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + struct MERCHANT_WIREFORMAT_Sepa *wf; + + wf = GNUNET_new (struct MERCHANT_WIREFORMAT_Sepa); + EXITIF (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, + "wire-sepa", + "IBAN", + &wf->iban)); + EXITIF (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, + "wire-sepa", + "NAME", + &wf->name)); + EXITIF (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, + "wire-sepa", + "BIC", + &wf->bic)); + return wf; + + EXITIF_exit: + GNUNET_free_non_null (wf->iban); + GNUNET_free_non_null (wf->name); + GNUNET_free_non_null (wf->bic); + GNUNET_free (wf); + return NULL; + +} + + +/** + * Destroy and free resouces occupied by the wireformat structure + * + * @param wf the wireformat structure + */ +void +TALER_MERCHANT_destroy_wireformat_sepa (struct MERCHANT_WIREFORMAT_Sepa *wf) +{ + GNUNET_free_non_null (wf->iban); + GNUNET_free_non_null (wf->name); + GNUNET_free_non_null (wf->bic); + GNUNET_free (wf); +} + +/* end of merchant.c */ diff --git a/src/merchant/merchant.h b/src/merchant/merchant.h new file mode 100644 index 00000000..c66131ed --- /dev/null +++ b/src/merchant/merchant.h @@ -0,0 +1,110 @@ +/* + This file is part of TALER + (C) 2014 Christian Grothoff (and other contributing authors) + + TALER 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, or (at your option) any later version. + + TALER 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 + TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> +*/ + +/** + * @file merchant/merchant.c + * @brief Common utility functions for merchant + * @author Sree Harsha Totakura <sreeharsha@totakura.in> + */ + +#ifndef MERCHANT_H +#define MERCHANT_H + +#include <gnunet/gnunet_common.h> +#include <gnunet/gnunet_crypto_lib.h> + +/** + * A mint + */ +struct MERCHANT_MintInfo { + /** + * Hostname + */ + char *hostname; + + /** + * The public key of the mint + */ + struct GNUNET_CRYPTO_EddsaPublicKey pubkey; + + /** + * The port where the mint's service is running + */ + uint16_t port; + +}; + + +/** + * Parses mints from the configuration. + * + * @param cfg the configuration + * @param mints the array of mints upon successful parsing. Will be NULL upon + * error. + * @return the number of mints in the above array; GNUNET_SYSERR upon error in + * parsing. + */ +int +TALER_MERCHANT_parse_mints (const struct GNUNET_CONFIGURATION_Handle *cfg, + struct MERCHANT_MintInfo **mints); + + +GNUNET_NETWORK_STRUCT_BEGIN +struct MERCHANT_WIREFORMAT_Sepa +{ + /** + * The international bank account number + */ + char *iban; + + /** + * Name of the bank account holder + */ + char *name; + + /** + *The bank identification code + */ + char *bic; + + /** + * The latest payout date when the payment corresponding to this account has + * to take place. A value of 0 indicates a transfer as soon as possible. + */ + struct GNUNET_TIME_AbsoluteNBO payout; +}; +GNUNET_NETWORK_STRUCT_END + +/** + * Parse the SEPA information from the configuration. If any of the required + * fileds is missing return NULL. + * + * @param cfg the configuration + * @return Sepa details as a structure; NULL upon error + */ +struct MERCHANT_WIREFORMAT_Sepa * +TALER_MERCHANT_parse_wireformat_sepa (const struct GNUNET_CONFIGURATION_Handle *cfg); + + +/** + * Destroy and free resouces occupied by the wireformat structure + * + * @param wf the wireformat structure + */ +void +TALER_MERCHANT_destroy_wireformat_sepa (struct MERCHANT_WIREFORMAT_Sepa *wf); + +#endif /* MERCHANT_H */ diff --git a/src/merchant/merchant_db.c b/src/merchant/merchant_db.c new file mode 100644 index 00000000..1b2fe720 --- /dev/null +++ b/src/merchant/merchant_db.c @@ -0,0 +1,347 @@ +/* + This file is part of TALER + (C) 2014 Christian Grothoff (and other contributing authors) + + TALER 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, or (at your option) any later version. + + TALER 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 + TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> +*/ + +/** + * @file merchant/merchant_db.c + * @brief database helper functions used by the merchant + * @author Sree Harsha Totakura <sreeharsha@totakura.in> + */ + +#include "platform.h" +#include <gnunet/gnunet_util_lib.h> +#include <taler/taler_util.h> +#include <taler/taler_db_lib.h> +#include "merchant_db.h" + + +#define PQSQL_strerror(kind, cmd, res) \ + GNUNET_log_from (kind, "merchant-db", \ + "SQL %s failed at %s:%u with error: %s", \ + cmd, __FILE__, __LINE__, PQresultErrorMessage (res)); + +/** + * Shorthand for exit jumps. + */ +#define EXITIF(cond) \ + do { \ + if (cond) { GNUNET_break (0); goto EXITIF_exit; } \ + } while (0) + + +/** + * Connect to postgresql database + * + * @param cfg the configuration handle + * @return connection to the postgresql database; NULL upon error + */ +PGconn * +MERCHANT_DB_connect (const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + return GNUNET_POSTGRES_connect (cfg, "merchant-db"); +} + + +/** + * Disconnect from the database + * + * @param conn database handle to close + */ +void +MERCHANT_DB_disconnect (PGconn *conn) +{ + PQfinish (conn); +} + + +/** + * Initialise merchant tables + * + * @param conn the connection handle to postgres db. + * @param tmp GNUNET_YES if the tables are to be made temporary i.e. their + * contents are dropped when the @a conn is closed + * @return GNUNET_OK upon success; GNUNET_SYSERR upon failure + */ +int +MERCHANT_DB_initialise (PGconn *conn, int tmp) +{ + const char *tmp_str = (1 == tmp) ? "TEMPORARY" : ""; + char *sql; + PGresult *res; + ExecStatusType status; + int ret; + + res = NULL; + (void) GNUNET_asprintf (&sql, + "BEGIN TRANSACTION;" + "CREATE %1$s TABLE IF NOT EXISTS contracts (" + "transaction_id SERIAL8 PRIMARY KEY," + "amount INT4 NOT NULL," + "amount_fraction INT4 NOT NULL," + "description TEXT NOT NULL," + "nounce BYTEA NOT NULL," + "expiry INT8 NOT NULL," + "product INT8 NOT NULL);" + "CREATE %1$s TABLE IF NOT EXISTS checkouts (" + "coin_pub BYTEA PRIMARY KEY," + "transaction_id INT8 REFERENCES contracts(transaction_id)," + "amount INT4 NOT NULL," + "amount_fraction INT4 NOT NULL," + "coin_sig BYTEA NOT NULL);", + tmp_str); + ret = GNUNET_POSTGRES_exec (conn, sql); + (void) GNUNET_POSTGRES_exec (conn, + (GNUNET_OK == ret) ? "COMMIT;" : "ROLLBACK"); + GNUNET_free (sql); + if (GNUNET_OK != ret) + return ret; + + while (NULL != (res = PQgetResult (conn))) + { + status = PQresultStatus (res); + PQclear (res); + } + + EXITIF (NULL == (res = PQprepare + (conn, + "contract_create", + "INSERT INTO contracts" + "(amount, amount_fraction, description," + "nounce, expiry, product) VALUES" + "($1, $2, $3, $4, $5, $6)" + "RETURNING transaction_id", + 6, NULL))); + EXITIF (PGRES_COMMAND_OK != (status = PQresultStatus(res))); + PQclear (res); + + EXITIF (NULL == (res = PQprepare + (conn, + "get_contract_product", + "SELECT (" + "product" + ") FROM contracts " + "WHERE (" + "transaction_id=$1" + ")", + 1, NULL))); + EXITIF (PGRES_COMMAND_OK != (status = PQresultStatus(res))); + PQclear (res); + + EXITIF (NULL == (res = PQprepare + (conn, + "checkout_create", + "INSERT INTO checkouts (" + "coin_pub," + "transaction_id," + "amount," + "amount_fraction," + "coin_sig" + ") VALUES (" + "$1, $2, $3, $4, $5" + ")", + 5, NULL))); + EXITIF (PGRES_COMMAND_OK != (status = PQresultStatus (res))); + PQclear (res); + + EXITIF (NULL == (res = PQprepare + (conn, + "get_checkout_product", + "SELECT (" + "product" + ") FROM contracts " + "WHERE " + "transaction_id IN (" + "SELECT (transaction_id) FROM checkouts " + "WHERE coin_pub=$1" + ")", + 1, NULL))); + EXITIF (PGRES_COMMAND_OK != (status = PQresultStatus (res))); + PQclear (res); + + return GNUNET_OK; + + EXITIF_exit: + if (NULL != res) + { + PQSQL_strerror (GNUNET_ERROR_TYPE_ERROR, "PQprepare", res); + PQclear (res); + } + return GNUNET_SYSERR; +} + + +/** + * Inserts a contract record into the database and if successfull returns the + * serial number of the inserted row. + * + * @param conn the database connection + * @param expiry the time when the contract will expire + * @param amount the taler amount corresponding to the contract + * @param desc descripition of the contract + * @param nounce a random 64-bit nounce + * @param product description to identify a product + * @return -1 upon error; the serial id of the inserted contract upon success + */ +long long +MERCHANT_DB_contract_create (PGconn *conn, + struct GNUNET_TIME_Absolute expiry, + struct TALER_Amount *amount, + const char *desc, + uint64_t nounce, + uint64_t product) +{ + PGresult *res; + uint64_t expiry_ms_nbo; + uint32_t value_nbo; + uint32_t fraction_nbo; + uint64_t nounce_nbo; + ExecStatusType status; + long long id; + struct TALER_DB_QueryParam params[] = { + TALER_DB_QUERY_PARAM_PTR (&value_nbo), + TALER_DB_QUERY_PARAM_PTR (&fraction_nbo), + TALER_DB_QUERY_PARAM_PTR_SIZED (desc, strlen(desc)), + TALER_DB_QUERY_PARAM_PTR (&nounce_nbo), + TALER_DB_QUERY_PARAM_PTR (&expiry_ms_nbo), + TALER_DB_QUERY_PARAM_PTR (&product), + TALER_DB_QUERY_PARAM_END + }; + struct TALER_DB_ResultSpec rs[] = { + TALER_DB_RESULT_SPEC("transaction_id", &id), + TALER_DB_RESULT_SPEC_END + }; + + expiry_ms_nbo = GNUNET_htonll (expiry.abs_value_us); + value_nbo = htonl (amount->value); + fraction_nbo = htonl (amount->fraction); + nounce_nbo = GNUNET_htonll (nounce); + product = GNUNET_htonll (product); + res = TALER_DB_exec_prepared (conn, "contract_create", params); + status = PQresultStatus (res); + EXITIF (PGRES_TUPLES_OK != status); + EXITIF (1 != PQntuples (res)); + EXITIF (GNUNET_YES != TALER_DB_extract_result (res, rs, 0)); + PQclear (res); + return GNUNET_ntohll ((uint64_t) id); + + EXITIF_exit: + PQclear (res); + return -1; +} + +long long +MERCHANT_DB_get_contract_product (PGconn *conn, + uint64_t contract_id) +{ + PGresult *res; + int64_t product; + ExecStatusType status; + struct TALER_DB_QueryParam params[] = { + TALER_DB_QUERY_PARAM_PTR (&contract_id), + TALER_DB_QUERY_PARAM_END + }; + struct TALER_DB_ResultSpec rs[] = { + TALER_DB_RESULT_SPEC("product", &product), + TALER_DB_RESULT_SPEC_END + }; + + contract_id = GNUNET_htonll (contract_id); + res = TALER_DB_exec_prepared (conn, "get_contract_product", params); + status = PQresultStatus (res); + EXITIF (PGRES_TUPLES_OK != status); + EXITIF (1 != PQntuples (res)); + EXITIF (GNUNET_YES != TALER_DB_extract_result (res, rs, 0)); + PQclear (res); + return GNUNET_ntohll ((uint64_t) product); + + EXITIF_exit: + PQclear (res); + return -1; +} + +unsigned int +MERCHANT_DB_checkout_create (PGconn *conn, + struct GNUNET_CRYPTO_EddsaPublicKey *coin_pub, + uint64_t transaction_id, + struct TALER_Amount *amount, + struct GNUNET_CRYPTO_EddsaSignature *coin_sig) +{ + PGresult *res; + ExecStatusType status; + uint32_t value_nbo; + uint32_t fraction_nbo; + struct TALER_DB_QueryParam params[] = { + TALER_DB_QUERY_PARAM_PTR (coin_pub), + TALER_DB_QUERY_PARAM_PTR (&transaction_id), + TALER_DB_QUERY_PARAM_PTR (&value_nbo), + TALER_DB_QUERY_PARAM_PTR (&fraction_nbo), + TALER_DB_QUERY_PARAM_PTR (coin_sig), + TALER_DB_QUERY_PARAM_END + }; + + transaction_id = GNUNET_htonll (transaction_id); + value_nbo = htonl (amount->value); + fraction_nbo = htonl (amount->fraction); + res = TALER_DB_exec_prepared (conn, "checkout_create", params); + status = PQresultStatus (res); + EXITIF (PGRES_COMMAND_OK != status); + PQclear (res); + return GNUNET_OK; + + EXITIF_exit: + PQclear (res); + return GNUNET_SYSERR; +} + + +long long +MERCHANT_DB_get_checkout_product (PGconn *conn, + struct GNUNET_CRYPTO_EddsaPublicKey *coin_pub) +{ + PGresult *res; + ExecStatusType status; + uint64_t product; + struct TALER_DB_QueryParam params[] = { + TALER_DB_QUERY_PARAM_PTR (coin_pub), + TALER_DB_QUERY_PARAM_END + }; + struct TALER_DB_ResultSpec rs[] = { + TALER_DB_RESULT_SPEC("product", &product), + TALER_DB_RESULT_SPEC_END + }; + + product = -1; + res = TALER_DB_exec_prepared (conn, "get_checkout_product", params); + status = PQresultStatus (res); + EXITIF (PGRES_TUPLES_OK != status); + if (0 == PQntuples (res)) + { + char *coin_pub_enc; + coin_pub_enc = GNUNET_CRYPTO_eddsa_public_key_to_string (coin_pub); + LOG_DEBUG ("Checkout not found for given coin: %s\n", + coin_pub_enc); + GNUNET_free (coin_pub_enc); + goto EXITIF_exit; + } + EXITIF (1 != PQntuples (res)); + EXITIF (GNUNET_YES != TALER_DB_extract_result (res, rs, 0)); + PQclear (res); + return GNUNET_ntohll ((uint64_t) product); + + EXITIF_exit: + PQclear (res); + return -1; +} +/* end of merchant-db.c */ diff --git a/src/merchant/merchant_db.h b/src/merchant/merchant_db.h new file mode 100644 index 00000000..734d547f --- /dev/null +++ b/src/merchant/merchant_db.h @@ -0,0 +1,98 @@ +/* + This file is part of TALER + (C) 2014 Christian Grothoff (and other contributing authors) + + TALER 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, or (at your option) any later version. + + TALER 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 + TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> +*/ + +/** + * @file merchant/merchant_db.h + * @brief database helper functions used by the merchant + * @author Sree Harsha Totakura <sreeharsha@totakura.in> + */ + +#ifndef MERCHANT_DB_H +#define MERCHANT_DB_H + +#include <gnunet/gnunet_postgres_lib.h> +#include <taler/taler_util.h> + +/** + * Connect to postgresql database + * + * @param cfg the configuration handle + * @return connection to the postgresql database; NULL upon error + */ +PGconn * +MERCHANT_DB_connect (const struct GNUNET_CONFIGURATION_Handle *cfg); + + +/** + * Disconnect from the database + * + * @param conn database handle to close + */ +void +MERCHANT_DB_disconnect (PGconn *conn); + + +/** + * Initialise merchant tables + * + * @param conn the connection handle to postgres db. + * @param tmp GNUNET_YES if the tables are to be made temporary i.e. their + * contents are dropped when the @a conn is closed + * @return GNUNET_OK upon success; GNUNET_SYSERR upon failure + */ +int +MERCHANT_DB_initialise (PGconn *conn, int tmp); + + +/** + * Inserts a contract record into the database and if successfull returns the + * serial number of the inserted row. + * + * @param conn the database connection + * @param expiry the time when the contract will expire + * @param amount the taler amount corresponding to the contract + * @param desc descripition of the contract + * @param nounce a random 64-bit nounce + * @param product description to identify a product + * @return -1 upon error; the serial id of the inserted contract upon success + */ +long long +MERCHANT_DB_contract_create (PGconn *conn, + struct GNUNET_TIME_Absolute expiry, + struct TALER_Amount *amount, + const char *desc, + uint64_t nounce, + uint64_t product); + +long long +MERCHANT_DB_get_contract_product (PGconn *conn, + uint64_t contract_id); + +unsigned int +MERCHANT_DB_checkout_create (PGconn *conn, + struct GNUNET_CRYPTO_EddsaPublicKey *coin_pub, + uint64_t transaction_id, + struct TALER_Amount *amount, + struct GNUNET_CRYPTO_EddsaSignature *coin_sig); + + +long long +MERCHANT_DB_get_checkout_product (PGconn *conn, + struct GNUNET_CRYPTO_EddsaPublicKey *coin_pub); + +#endif /* MERCHANT_DB_H */ + +/* end of merchant-db.h */ diff --git a/src/merchant/taler_merchant_dbinit.c b/src/merchant/taler_merchant_dbinit.c new file mode 100644 index 00000000..e6d0af9d --- /dev/null +++ b/src/merchant/taler_merchant_dbinit.c @@ -0,0 +1,79 @@ +/* + This file is part of TALER + (C) 2014 Christian Grothoff (and other contributing authors) + + TALER 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, or (at your option) any later version. + + TALER 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 + TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> +*/ + +/** + * @file merchant/taler_merchant_dbinit.c + * @brief Program to initialise merchant database + * @author Sree Harsha Totakura <sreeharsha@totakura.in> + */ + +#include "platform.h" +#include <gnunet/gnunet_util_lib.h> +#include "merchant_db.h" + + +/** + * Global execution result + */ +static int result; + + +/** + * Main function that will be run by the scheduler. + * + * @param cls closure + * @param args remaining command-line arguments + * @param cfgfile name of the configuration file used (for saving, can be NULL!) + * @param config configuration + */ +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *config) +{ + PGconn *conn; + + conn = MERCHANT_DB_connect (config); + if (NULL == conn) + return; + if (GNUNET_OK == MERCHANT_DB_initialise (conn, GNUNET_NO)) + result = GNUNET_OK; + MERCHANT_DB_disconnect (conn); +} + + +/** + * The main function + * + * @param argc number of arguments from the command line + * @param argv command line arguments + * @return 0 ok, 1 on error + */ +int +main (int argc, char *const *argv) +{ + static const struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + + result = GNUNET_SYSERR; + if (GNUNET_OK != + GNUNET_PROGRAM_run (argc, argv, "taler-merchant-dbinit", + gettext_noop + ("Initialise Taler Merchant's database"), + options, &run, NULL)) + return 3; + return (GNUNET_OK == result) ? 0 : 1; +} diff --git a/src/merchant/taler_merchant_serve.c b/src/merchant/taler_merchant_serve.c new file mode 100644 index 00000000..67738886 --- /dev/null +++ b/src/merchant/taler_merchant_serve.c @@ -0,0 +1,1559 @@ +/* + This file is part of TALER + (C) 2014 Christian Grothoff (and other contributing authors) + + TALER 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, or (at your option) any later version. + + TALER 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 + TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> +*/ + +/** + * @file merchant/taler_merchant_serve.c + * @brief Reference implementation of the merchant's HTTP interface + * @author Sree Harsha Totakura <sreeharsha@totakura.in> + */ + + +#include "platform.h" +#include <gnunet/gnunet_util_lib.h> +#include <microhttpd.h> +#include <taler/taler_util.h> +#include "merchant.h" +#include "merchant_db.h" +#include <taler/taler_mint_service.h> +#include <taler/taler_signatures.h> +#include <taler/taler_json_lib.h> + + +/** + * Shorthand for exit jumps. + */ +#define EXITIF(cond) \ + do { \ + if (cond) { GNUNET_break (0); goto EXITIF_exit; } \ + } while (0) + +/** + * Shorthand for exit jumps due to protocol exceptions resulting from client's + * mistakes + */ +#define EXITIF_OP(cond) \ + do { \ + if (cond) { GNUNET_break_op (0); goto EXITIF_exit; } \ + } while (0) + +/** + * Print JSON parsing related error information + */ +#define WARN_JSON(error) \ + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, \ + "JSON parsing failed at %s:%u: %s (%s)", \ + __FILE__, __LINE__, error.text, error.source) + +/** + * Macro to round microseconds to seconds in GNUNET_TIME_* structs. + */ +#define ROUND_TO_SECS(name,us_field) name.us_field -= name.us_field % (1000 * 1000) + + +struct ContractData +{ + char *product; +}; + + +GNUNET_NETWORK_STRUCT_BEGIN + +struct Contract +{ + /** + * The signature of the merchant for this contract + */ + struct GNUNET_CRYPTO_EddsaSignature sig; + + /** + * Purpose header for the signature over contract + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + + /** + * The transaction identifier + */ + char m[13]; + + /** + * Expiry time + */ + struct GNUNET_TIME_AbsoluteNBO t; + + /** + * The invoice amount + */ + struct TALER_AmountNBO amount; + + /** + * The hash of the preferred wire format + nounce + */ + struct GNUNET_HashCode h_wire; + + /** + * The contract data + */ + char a[]; +}; + +GNUNET_NETWORK_STRUCT_END + +/** + * A download object + */ +struct Download { + struct Download *next; + struct Download *prev; + char *filename; + struct MHD_Response *resp; + unsigned int id; +}; + +/** + * DLL for downloadable objects + */ +struct Download *dwn_head; +struct Download *dwn_tail; + +/** + * MHD response object for listing all products + */ +struct MHD_Response *list_products_resp; + +/** + * Number of files we make available for downloading + */ +static unsigned int ndownloads; + + +/** + * Context information of the mints we trust + */ +struct Mint +{ + /** + * Public key of this mint + */ + struct GNUNET_CRYPTO_EddsaPublicKey pubkey; + + /** + * Connection handle to this mint + */ + struct TALER_MINT_Handle *conn; +}; + +/** + * Hashmap to store the mint context information + */ +static struct GNUNET_CONTAINER_MultiPeerMap *mints_map; + +/** + * Our private key + */ +struct GNUNET_CRYPTO_EddsaPrivateKey *privkey; + +/** + * Connection handle to the our database + */ +PGconn *db_conn; + +/** + * The MHD Daemon + */ +static struct MHD_Daemon *mhd; + +/** + * Our wireformat + */ +static struct MERCHANT_WIREFORMAT_Sepa *wire; + +/** + * Hash of the wireformat + */ +static struct GNUNET_HashCode h_wire; + +/** + * Shutdown task identifier + */ +static struct GNUNET_SCHEDULER_Task *shutdown_task; + +/** + * Task for calling the select on MHD's sockets + */ +static struct GNUNET_SCHEDULER_Task *select_task; + +/** + * The port we are running on + */ +static long long unsigned port; + +/** + * Mint context + */ +static struct TALER_MINT_Context *mctx; + +/** + * Our hostname + */ +static char *hostname; + +/** + * Directory of data items to serve + */ +static char *data_dir; + +/** + * Should we do a dry run where temporary tables are used for storing the data. + */ +static int dry; + +/** + * Global return code + */ +static int result; + + + +/** + * Send JSON object as response. Decreases the reference count of the + * JSON object. + * + * @param connection the MHD connection + * @param json the json object + * @param status_code the http status code + * @return MHD result code + */ +static int +send_response_json (struct MHD_Connection *connection, + json_t *json, + unsigned int status_code) +{ + struct MHD_Response *resp; + char *json_str; + + json_str = json_dumps (json, JSON_INDENT(2)); + json_decref (json); + resp = MHD_create_response_from_buffer (strlen (json_str), json_str, + MHD_RESPMEM_MUST_FREE); + if (NULL == resp) + return MHD_NO; + return MHD_queue_response (connection, status_code, resp); +} + + +/* ************ JSON post-processing logic; FIXME: why do we use JSON here!? ********** */ + + +/** + * Initial size for POST + * request buffer. + */ +#define REQUEST_BUFFER_INITIAL 1024 + +/** + * Maximum POST request size + */ +#define REQUEST_BUFFER_MAX (1024*1024) + + +/** + * Buffer for POST requests. + */ +struct Buffer +{ + /** + * Allocated memory + */ + char *data; + + /** + * Number of valid bytes in buffer. + */ + size_t fill; + + /** + * Number of allocated bytes in buffer. + */ + size_t alloc; +}; + + +/** + * Initialize a buffer. + * + * @param buf the buffer to initialize + * @param data the initial data + * @param data_size size of the initial data + * @param alloc_size size of the buffer + * @param max_size maximum size that the buffer can grow to + * @return a GNUnet result code + */ +static int +buffer_init (struct Buffer *buf, const void *data, size_t data_size, size_t alloc_size, size_t max_size) +{ + if (data_size > max_size || alloc_size > max_size) + return GNUNET_SYSERR; + if (data_size > alloc_size) + alloc_size = data_size; + buf->data = GNUNET_malloc (alloc_size); + memcpy (buf->data, data, data_size); + return GNUNET_OK; +} + + +/** + * Free the data in a buffer. Does *not* free + * the buffer object itself. + * + * @param buf buffer to de-initialize + */ +static void +buffer_deinit (struct Buffer *buf) +{ + GNUNET_free (buf->data); + buf->data = NULL; +} + + +/** + * Append data to a buffer, growing the buffer if necessary. + * + * @param buf the buffer to append to + * @param data the data to append + * @param size the size of @a data + * @param max_size maximum size that the buffer can grow to + * @return GNUNET_OK on success, + * GNUNET_NO if the buffer can't accomodate for the new data + * GNUNET_SYSERR on fatal error (out of memory?) + */ +static int +buffer_append (struct Buffer *buf, const void *data, size_t data_size, size_t max_size) +{ + if (buf->fill + data_size > max_size) + return GNUNET_NO; + if (data_size + buf->fill > buf->alloc) + { + char *new_buf; + size_t new_size = buf->alloc; + while (new_size < buf->fill + data_size) + new_size += 2; + if (new_size > max_size) + return GNUNET_NO; + new_buf = GNUNET_malloc (new_size); + memcpy (new_buf, buf->data, buf->fill); + buf->data = new_buf; + buf->alloc = new_size; + } + memcpy (buf->data + buf->fill, data, data_size); + buf->fill += data_size; + return GNUNET_OK; +} + + + +/** + * Process a POST request containing a JSON object. + * + * @param connection the MHD connection + * @param con_cs the closure (contains a 'struct Buffer *') + * @param upload_data the POST data + * @param upload_data_size the POST data size + * @param json the JSON object for a completed request + * + * @returns + * GNUNET_YES if json object was parsed + * GNUNET_NO is request incomplete or invalid + * GNUNET_SYSERR on internal error + */ +static int +process_post_json (struct MHD_Connection *connection, + void **con_cls, + const char *upload_data, + size_t *upload_data_size, + json_t **json) +{ + struct Buffer *r = *con_cls; + + if (NULL == *con_cls) + { + /* We are seeing a fresh POST request. */ + + r = GNUNET_new (struct Buffer); + if (GNUNET_OK != buffer_init (r, upload_data, *upload_data_size, + REQUEST_BUFFER_INITIAL, REQUEST_BUFFER_MAX)) + { + *con_cls = NULL; + buffer_deinit (r); + GNUNET_free (r); + return GNUNET_SYSERR; + } + *upload_data_size = 0; + *con_cls = r; + return GNUNET_NO; + } + if (0 != *upload_data_size) + { + /* We are seeing an old request with more data available. */ + + if (GNUNET_OK != buffer_append (r, upload_data, *upload_data_size, + REQUEST_BUFFER_MAX)) + { + /* Request too long or we're out of memory. */ + + *con_cls = NULL; + buffer_deinit (r); + GNUNET_free (r); + return GNUNET_SYSERR; + } + *upload_data_size = 0; + return GNUNET_NO; + } + + /* We have seen the whole request. */ + + *json = json_loadb (r->data, r->fill, 0, NULL); + buffer_deinit (r); + GNUNET_free (r); + if (NULL == *json) + { + struct MHD_Response *resp; + int ret; + + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Can't parse JSON request body\n"); + resp = MHD_create_response_from_buffer (strlen ("parse error"), + "parse error", + MHD_RESPMEM_PERSISTENT); + ret = MHD_queue_response (connection, + MHD_HTTP_BAD_REQUEST, + resp); + MHD_destroy_response (resp); + return ret; + } + *con_cls = NULL; + + return GNUNET_YES; +} + + +/* ************** END of JSON POST processing logic ************ */ + + +static struct GNUNET_HashCode +hash_wireformat (uint64_t nounce) +{ + struct TALER_HashContext hc; + struct GNUNET_HashCode hash; + + TALER_hash_context_start (&hc); + TALER_hash_context_read (&hc, wire->iban, strlen (wire->iban)); + TALER_hash_context_read (&hc, wire->name, strlen (wire->name)); + TALER_hash_context_read (&hc, wire->bic, strlen (wire->bic)); + nounce = GNUNET_htonll (nounce); + TALER_hash_context_read (&hc, &nounce, sizeof (nounce)); + TALER_hash_context_finish (&hc, &hash); + return hash; +} + + +static json_t * +build_json_contract (struct Contract *contract) +{ + return json_pack ("{s:s, s:o, s:o, s:s, s:o, s:o}", + "transaction_id", contract->m, + "expiry", TALER_JSON_from_abs (GNUNET_TIME_absolute_ntoh (contract->t)), + "amount", TALER_JSON_from_amount (TALER_amount_ntoh (contract->amount)), + "description", contract->a, + "H_wire", TALER_JSON_from_data (&contract->h_wire, sizeof (struct GNUNET_HashCode)), + "msig", TALER_JSON_from_data (&contract->sig, sizeof (struct GNUNET_CRYPTO_EddsaSignature))); +} + +/** + * Cleeanup entries in the peer map. + * + * @param cls closure + * @param key current public key + * @param value value in the hash map + * @return #GNUNET_YES if we should continue to + * iterate, + * #GNUNET_NO if not. + */ +static int +mints_cleanup_iterator (void *cls, + const struct GNUNET_PeerIdentity *key, + void *value) +{ + struct Mint *mint = value; + + if (NULL != mint->conn) + TALER_MINT_disconnect (mint->conn); + GNUNET_CONTAINER_multipeermap_remove (mints_map, key, mint); + GNUNET_free (mint); + return GNUNET_YES; +} + + +/** + * Shutdown task + * + * @param cls NULL + * @param tc scheduler task context + */ +static void +do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct Download *dwn; + + shutdown_task = NULL; + if (NULL != select_task) + { + GNUNET_SCHEDULER_cancel (select_task); + select_task = NULL; + } + if (NULL != list_products_resp) + { + MHD_destroy_response (list_products_resp); + list_products_resp = NULL; + } + if (NULL != mhd) + { + MHD_stop_daemon (mhd); + mhd = NULL; + } + if (NULL != db_conn) + { + MERCHANT_DB_disconnect (db_conn); + db_conn = NULL; + } + if (NULL != mints_map) + { + GNUNET_CONTAINER_multipeermap_iterate (mints_map, + &mints_cleanup_iterator, + NULL); + GNUNET_CONTAINER_multipeermap_destroy (mints_map); + mints_map = NULL; + } + if (NULL != mctx) + { + TALER_MINT_cleanup (mctx); + mctx = NULL; + } + if (NULL != wire) + { + TALER_MERCHANT_destroy_wireformat_sepa (wire); + wire = NULL; + } + while (NULL != (dwn = dwn_head)) + { + GNUNET_CONTAINER_DLL_remove (dwn_head, dwn_tail, dwn); + if (NULL != dwn->resp) + MHD_destroy_response (dwn->resp); + GNUNET_free (dwn->filename); + GNUNET_free (dwn); + } +} + + +/** + * Get the MHD's sockets which are to be called with select() and schedule the + * select task. + * + * @return GNUNET_YES upon success; GNUNET_NO upon error, in this case the + * select task will not be queued. + */ +static int +poll_mhd (); + + +/** + * One of the MHD's sockets are ready. Call MHD_run_from_select (). + * + * @param cls NULL + * @param tc scheduler task context + */ +static void +run_mhd (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + fd_set fd_rs; + fd_set fd_ws; + select_task = NULL; + if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason)) + return; + FD_ZERO (&fd_rs); + FD_ZERO (&fd_ws); + if (0 != (GNUNET_SCHEDULER_REASON_READ_READY & tc->reason)) + fd_rs = tc->read_ready->sds; + if (0 != (GNUNET_SCHEDULER_REASON_WRITE_READY & tc->reason)) + fd_ws = tc->write_ready->sds; + EXITIF (MHD_YES != MHD_run_from_select (mhd, + &fd_rs, + &fd_ws, + NULL)); + EXITIF (GNUNET_NO == poll_mhd ()); + return; + + EXITIF_exit: + result = GNUNET_SYSERR; + GNUNET_SCHEDULER_shutdown (); +} + + +/** + * Get the MHD's sockets which are to be called with select() and schedule the + * select task. + * + * @return GNUNET_YES upon success; GNUNET_NO upon error, in this case the + * select task will not be queued. + */ +static int +poll_mhd () +{ + struct GNUNET_NETWORK_FDSet rs; + struct GNUNET_NETWORK_FDSet ws; + fd_set fd_rs; + fd_set fd_ws; + fd_set fd_es; + struct GNUNET_TIME_Relative delay; + unsigned long long timeout; + int max_fd; + + FD_ZERO (&fd_rs); + FD_ZERO (&fd_ws); + FD_ZERO (&fd_es); + max_fd = 0; + if (MHD_YES != MHD_get_fdset (mhd, + &fd_rs, + &fd_ws, + &fd_es, + &max_fd)) + return GNUNET_SYSERR; + GNUNET_NETWORK_fdset_zero (&rs); + GNUNET_NETWORK_fdset_zero (&ws); + GNUNET_NETWORK_fdset_copy_native (&rs, &fd_rs, max_fd + 1); + GNUNET_NETWORK_fdset_copy_native (&ws, &fd_ws, max_fd + 1); + if (MHD_NO == MHD_get_timeout (mhd, &timeout)) + timeout = 0; + if (0 == timeout) + delay = GNUNET_TIME_UNIT_FOREVER_REL; + else + delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, + timeout); + if (NULL != select_task) + GNUNET_SCHEDULER_cancel (select_task); + select_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_KEEP, + delay, + &rs, + &ws, + &run_mhd, + NULL); + return GNUNET_OK; +} + +static int +failure_resp (struct MHD_Connection *connection, unsigned int status) +{ + static char page_404[]="\ +<!DOCTYPE html> \ +<html><title>Resource not found</title><body><center> \ +<h3>The resource you are looking for is not found.</h3> \ +</center></body></html>"; + static char page_500[]="\ +<!DOCTYPE html> <html><title>Internal Server Error</title><body><center> \ +<h3>The server experienced an internal error and hence cannot serve your \ +request</h3></center></body></html>"; + struct MHD_Response *resp; + char *page; + size_t size; +#define PAGE(number) \ + do {page=page_ ## number; size=sizeof(page_ ## number)-1;} while(0) + + GNUNET_assert (400 <= status); + resp = NULL; + switch (status) + { + case 404: + PAGE(404); + break; + default: + status = 500; + case 500: + PAGE(500); + } +#undef PAGE + + EXITIF (NULL == (resp = MHD_create_response_from_buffer (size, + page, + MHD_RESPMEM_PERSISTENT))); + EXITIF (MHD_YES != MHD_queue_response (connection, status, resp)); + MHD_destroy_response (resp); + return GNUNET_OK; + + EXITIF_exit: + if (NULL != resp) + MHD_destroy_response (resp); + return GNUNET_SYSERR; +} + + +/** + * Iterator over key-value pairs. This iterator + * can be used to iterate over all of the cookies, + * headers, or POST-data fields of a request, and + * also to iterate over the headers that have been + * added to a response. + * + * @param cls closure + * @param kind kind of the header we are looking at + * @param key key for the value, can be an empty string + * @param value corresponding value, can be NULL + * @return #MHD_YES to continue iterating, + * #MHD_NO to abort the iteration + * @ingroup request + */ +static int +get_contract_values_iter (void *cls, + enum MHD_ValueKind kind, + const char *key, const char *value) +{ + unsigned long long id; + uint64_t *product = cls; + +#define STR_PRODUCT "product" + if (0 == strncasecmp (key, STR_PRODUCT, sizeof (STR_PRODUCT) - 1)) + { + if (1 > sscanf (value, "%llu", &id)) + return GNUNET_NO; + *product = (uint64_t) id; + } + return GNUNET_YES; +} + +#if 0 +static const char * +uint64_to_enc (uint64_t i) +{ + static char buf[14]; + i = GNUNET_htonll (i); + GNUNET_break (NULL != + GNUNET_STRINGS_data_to_string (&i, sizeof (i), buf, sizeof (buf))); + buf[13] = '\0'; + return buf; +} + +static uint64_t +enc_to_uint64 (const char *enc) +{ + uint64_t i; + GNUNET_break (GNUNET_OK == + GNUNET_STRINGS_string_to_data (enc, strlen(enc), &i, sizeof + (i))); + return GNUNET_ntohll (i); +} +#endif + +/** + * Prepare a contract, store it in database and send the corresponding JSON. + * + * @param connection MHD connection handle + * @param _resp pointer to hold the result response upon success + * @return the status code 200 when a contract is generated; 404 when the + * product is not found or upon other errors. + */ +static unsigned int +handle_get_contract (struct MHD_Connection *connection, + struct MHD_Response **_resp) +{ + struct MHD_Response *resp; + struct Contract *contract; + struct GNUNET_TIME_Absolute expiry; + struct TALER_Amount amount; + char *template = "A contract from GNUnet e.V thanking you for a" + " donation of the aforementioned amount. As a token of gratitude, upon" + " successful payment, you may download your image at " + "`http://%s:%u/download?ref=[]'"; + char *desc; + json_t *json; + char *json_str; + uint64_t nounce; + uint64_t product; + uint64_t contract_id_nbo; + long long contract_id; + unsigned int ret; + + resp = NULL; + contract = NULL; + desc = NULL; + ret = 400; + product = UINT64_MAX; + MHD_get_connection_values (connection, MHD_GET_ARGUMENT_KIND, + &get_contract_values_iter, &product); + if (UINT64_MAX == product) + goto EXITIF_exit; + + expiry = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (), + GNUNET_TIME_UNIT_DAYS); + ROUND_TO_SECS (expiry, abs_value_us); + amount.value = 1; + amount.fraction = 0; + strcpy (amount.currency, "EUR"); + nounce = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_NONCE, UINT64_MAX); + + /* Prepare contract */ + GNUNET_asprintf (&desc, template, hostname, port); + contract_id = MERCHANT_DB_contract_create (db_conn, + expiry, + &amount, + desc, + nounce, + product); + EXITIF (-1 == contract_id); + contract_id_nbo = GNUNET_htonll ((uint64_t) contract_id); + contract = GNUNET_malloc (sizeof (struct Contract) + strlen (desc) + 1); + contract->purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_CONTRACT); + contract->purpose.size = htonl (sizeof (struct Contract) + - offsetof (struct Contract, purpose) + + strlen (desc) + 1); + GNUNET_STRINGS_data_to_string (&contract_id_nbo, sizeof (contract_id_nbo), + contract->m, sizeof (contract->m)); + contract->t = GNUNET_TIME_absolute_hton (expiry); + (void) strcpy (contract->a, desc); + contract->h_wire = hash_wireformat (nounce); + contract->amount = TALER_amount_hton (amount); + GNUNET_CRYPTO_eddsa_sign (privkey, &contract->purpose, &contract->sig); + json = build_json_contract (contract); + json_str = json_dumps (json, JSON_INDENT(2)); + json_decref (json); + resp = MHD_create_response_from_buffer (strlen (json_str), json_str, + MHD_RESPMEM_MUST_FREE); + ret = 200; + + EXITIF_exit: + GNUNET_free_non_null (desc); + if (NULL != resp) + *_resp = resp; + if (NULL != contract) + { + GNUNET_free (contract); + } + return ret; +} + +static struct Download * +find_product (unsigned int id) +{ + struct Download *dwn; + + for (dwn = dwn_head; NULL != dwn; dwn = dwn->next) + { + if (dwn->id == id) + return dwn; + } + return NULL; +} + + +static int +get_download_ref (void *cls, + enum MHD_ValueKind kind, + const char *key, const char *value) +{ + char **coin_pub_enc = cls; + + if (0 == strncasecmp (key, "ref", sizeof ("ref"))) + { + *coin_pub_enc = GNUNET_strdup (value); + return MHD_NO; + } + return MHD_YES; +} + +static unsigned int +handle_download (struct MHD_Connection *conn, + struct MHD_Response **_resp) +{ + char *coin_pub_enc; + struct Download *item; + struct GNUNET_DISK_FileHandle *fh; + struct GNUNET_CRYPTO_EddsaPublicKey coin_pub; + long long product_id; + off_t size; + int ret; + + coin_pub_enc = NULL; + ret = MHD_HTTP_NOT_FOUND; + MHD_get_connection_values (conn, MHD_GET_ARGUMENT_KIND, + &get_download_ref, &coin_pub_enc); + LOG_WARNING ("Trying to start downloading with coin: %s\n", coin_pub_enc); + EXITIF (NULL == coin_pub_enc); + EXITIF (GNUNET_SYSERR == + GNUNET_CRYPTO_eddsa_public_key_from_string (coin_pub_enc, + strlen (coin_pub_enc), + &coin_pub)); + product_id = MERCHANT_DB_get_checkout_product (db_conn, + &coin_pub); + EXITIF (-1 == product_id); + EXITIF (NULL == (item = find_product ((unsigned int) product_id))); + if (NULL != item->resp) + { + *_resp = item->resp; + ret = MHD_HTTP_OK; + goto EXITIF_exit; + } + fh = GNUNET_DISK_file_open (item->filename, + GNUNET_DISK_OPEN_READ, + GNUNET_DISK_PERM_USER_READ); + GNUNET_assert (NULL != fh); + GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_handle_size (fh, + &size)); + item->resp = MHD_create_response_from_fd (size, fh->fd); + GNUNET_assert (MHD_NO != MHD_add_response_header (item->resp, + "Content-Type", + "image/jpeg")); + GNUNET_free (fh); + + EXITIF_exit: + GNUNET_free_non_null (coin_pub_enc); + return ret; +} + +struct CheckoutCtx +{ + /* FIXME: Hook into a DLL for cleaner shutdown */ + struct MHD_Connection *conn; + struct TALER_MINT_DepositHandle *dh; + struct Download *product; + char *coin_pub_enc; + uint64_t transaction_id; + struct GNUNET_CRYPTO_EddsaPublicKey coin_pub; + struct GNUNET_CRYPTO_EddsaSignature coin_sig; + struct TALER_Amount amount; + struct GNUNET_SCHEDULER_Task *timeout_task; + +}; + + +/** + * Callbacks of this type are used to serve the result of submitting a deposit + * permission object to a mint + * + * @param cls closure + * @param status 1 for successful deposit, 2 for retry, 0 for failure + * @param obj the received JSON object; can be NULL if it cannot be constructed + * from the reply + * @param emsg in case of unsuccessful deposit, this contains a human readable + * explanation. + */ +static void +checkout_status (void *cls, int status, json_t *obj, char *emsg) +{ + struct CheckoutCtx *ctx = cls; + const char *tmplt_download_page = + "<!DOCTYPE HTML><html>" + "<body>You are being redirected to the product download page<br>" + "If your browser is unable to redirect, you may click " + "<a href=\"%s\">here</a> to download.</body>" + "</html>"; + char *download_page; + char *location; + struct MHD_Response *resp; + ssize_t size; + + LOG_DEBUG ("Processing checkout request reply\n"); + GNUNET_SCHEDULER_cancel (ctx->timeout_task); + ctx->timeout_task = NULL; + download_page = NULL; + location = NULL; + switch (status) + { + case 1: + { + struct GNUNET_CRYPTO_EddsaPublicKey coin_pub; + + GNUNET_assert (GNUNET_SYSERR != + GNUNET_CRYPTO_eddsa_public_key_from_string + (ctx->coin_pub_enc, + strlen (ctx->coin_pub_enc), + &coin_pub)); + /* FIXME: Put the contract into the checkout DB. */ + } + /* redirect with HTTP FOUND 302 to the product download page */ + GNUNET_assert (NULL != obj); + GNUNET_assert (0 < (size = GNUNET_asprintf (&location, + "/download?ref=%s", + ctx->coin_pub_enc))); + GNUNET_assert (0 < (size = GNUNET_asprintf (&download_page, + tmplt_download_page, + location))); + resp = MHD_create_response_from_buffer (size, + download_page, + MHD_RESPMEM_MUST_FREE); + /* IMP: do not free `download_page' */ + GNUNET_assert (NULL != resp); + GNUNET_assert (MHD_NO != MHD_add_response_header (resp, + "Location", + location)); + GNUNET_assert (MHD_YES == MHD_queue_response (ctx->conn, + MHD_HTTP_FOUND, + resp)); + MHD_destroy_response (resp); + GNUNET_free (location); + location = NULL; + resp = NULL; +#if 0 + struct Download *product; + struct GNUNET_DISK_FileHandle *fh; + GNUNET_assert (NULL != (product = ctx->product)); + if (NULL != product->resp) + { + MHD_queue_response (ctx->conn, MHD_HTTP_OK, product->resp); + break; + } + fh = GNUNET_DISK_file_open (product->filename, + GNUNET_DISK_OPEN_READ, + GNUNET_DISK_PERM_USER_READ); + GNUNET_assert (NULL != fh); + GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_handle_size (fh, + &size)); + product->resp = MHD_create_response_from_fd (size, fh->fd); + GNUNET_assert (MHD_NO != MHD_add_response_header (product->resp, + "Content-Type", + "image/jpeg")); + GNUNET_free (fh); + MHD_queue_response (ctx->conn, MHD_HTTP_OK, product->resp); +#endif + + break; + case 2: + send_response_json (ctx->conn, + json_pack ("{s:s}", "status", "pending"), + 200); /* FIXME: Send Image data */ + break; + case 0: + send_response_json (ctx->conn, + json_pack ("{s:s s:s}", + "status", "failed", + "error", (NULL != emsg) ? emsg : "unknown"), + 400); /* FIXME */ + break; + default: + GNUNET_assert (0); /* should never reach */ + } + GNUNET_free (ctx->coin_pub_enc); + GNUNET_free (ctx); + if (GNUNET_SYSERR == poll_mhd ()) + { + GNUNET_break (0); + GNUNET_SCHEDULER_shutdown (); + } +} + +static void +checkout_status_timedout (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct CheckoutCtx *ctx = cls; + + LOG_DEBUG ("Checkout request timed out\n"); + ctx->timeout_task = NULL; + TALER_MINT_deposit_submit_cancel (ctx->dh); + ctx->dh = NULL; + send_response_json (ctx->conn, + json_pack ("{s:s}", "error", "timeout"), + 400); /* FIXME */ + GNUNET_free (ctx->coin_pub_enc); + GNUNET_free (ctx); + EXITIF (GNUNET_SYSERR == poll_mhd ()); + return; + + EXITIF_exit: + GNUNET_SCHEDULER_shutdown (); +} + +static int +handle_checkout (struct MHD_Connection *conn, + json_t *checkout_json) +{ + struct CheckoutCtx *ctx; + const char *pkey_enc; + const char *tid_enc; + const char *emsg; + const char *coin_pub_enc; + const char *coin_sig_enc; + struct Mint *mint; + struct Download *product; + struct GNUNET_CRYPTO_EddsaPublicKey pkey; + struct GNUNET_CRYPTO_EddsaPublicKey coin_pub; + struct GNUNET_CRYPTO_EddsaSignature coin_sig; + uint64_t tid; + uint64_t product_id; + json_error_t jerror; + unsigned int status; + + coin_pub_enc = NULL; + emsg = "Public key of Mint is missing in the request"; + status = MHD_HTTP_BAD_REQUEST; + if (-1 == json_unpack_ex (checkout_json, + &jerror, + 0, + "{s:s s:s s:s s:s}", + "mint_pub", &pkey_enc, + "transaction_id", &tid_enc, + "coin_pub", &coin_pub_enc, + "coin_sig", &coin_sig_enc)) + { + WARN_JSON (jerror); + goto EXITIF_exit; + } + + EXITIF (GNUNET_OK != GNUNET_STRINGS_string_to_data + (tid_enc, strlen (tid_enc), &tid, sizeof (tid))); + tid = GNUNET_ntohll (tid); + + emsg = "Public key of the coin is missing/malformed in the request"; + EXITIF (NULL == coin_pub_enc); + EXITIF (GNUNET_SYSERR == + GNUNET_CRYPTO_eddsa_public_key_from_string (coin_pub_enc, + strlen (coin_pub_enc), + &coin_pub)); + + emsg = "Signature of the coin is missing/malformed in the request"; + EXITIF (NULL == coin_sig_enc); + EXITIF (GNUNET_SYSERR == + GNUNET_STRINGS_string_to_data (coin_sig_enc, strlen (coin_sig_enc), + &coin_sig, sizeof (coin_sig))); + + emsg = "Contract not found"; + status = MHD_HTTP_NOT_FOUND; + LOG_DEBUG ("Looking for product associated with transaction %u\n", tid); + EXITIF (-1 == (product_id = MERCHANT_DB_get_contract_product (db_conn, tid))); + + emsg = "Could not find the downloadable product. Sorry :("; + EXITIF (NULL == (product = find_product (product_id))); + + emsg = "Invalid public key given for a mint"; + EXITIF (52 != strlen (pkey_enc)); + EXITIF (GNUNET_SYSERR == GNUNET_STRINGS_string_to_data (pkey_enc, 52, + &pkey, sizeof (pkey))); + + emsg = "The provided mint is not trusted by us"; + status = MHD_HTTP_FORBIDDEN; + EXITIF (NULL == (mint = + GNUNET_CONTAINER_multipeermap_get (mints_map, + (const struct + GNUNET_PeerIdentity *) + &pkey))); + + LOG_DEBUG ("Creating a new checkout request\n"); + ctx = GNUNET_new (struct CheckoutCtx); + ctx->product = product; + ctx->conn = conn; + ctx->coin_pub_enc = GNUNET_strdup (coin_pub_enc); + ctx->transaction_id = tid; + ctx->coin_pub = coin_pub; + ctx->coin_sig = coin_sig; + /* FIXME: parse amount */ + /* ctx->amount = ?? */ + ctx->dh = TALER_MINT_deposit_submit_json (mint->conn, + checkout_status, + ctx, + checkout_json); + ctx->timeout_task = GNUNET_SCHEDULER_add_delayed + (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 3), + &checkout_status_timedout, ctx); + return MHD_YES; + + EXITIF_exit: + json_decref (checkout_json); + return send_response_json (conn, + json_pack ("{s:s s:s}", + "status", "failed", + "error", emsg), + status); +} + +/** + * A client has requested the given url using the given method + * (#MHD_HTTP_METHOD_GET, #MHD_HTTP_METHOD_PUT, + * #MHD_HTTP_METHOD_DELETE, #MHD_HTTP_METHOD_POST, etc). The callback + * must call MHD callbacks to provide content to give back to the + * client and return an HTTP status code (i.e. #MHD_HTTP_OK, + * #MHD_HTTP_NOT_FOUND, etc.). + * + * @param cls argument given together with the function + * pointer when the handler was registered with MHD + * @param url the requested url + * @param method the HTTP method used (#MHD_HTTP_METHOD_GET, + * #MHD_HTTP_METHOD_PUT, etc.) + * @param version the HTTP version string (i.e. + * #MHD_HTTP_VERSION_1_1) + * @param upload_data the data being uploaded (excluding HEADERS, + * for a POST that fits into memory and that is encoded + * with a supported encoding, the POST data will NOT be + * given in upload_data and is instead available as + * part of #MHD_get_connection_values; very large POST + * data *will* be made available incrementally in + * @a upload_data) + * @param upload_data_size set initially to the size of the + * @a upload_data provided; the method must update this + * value to the number of bytes NOT processed; + * @param con_cls pointer that the callback can set to some + * address and that will be preserved by MHD for future + * calls for this request; since the access handler may + * be called many times (i.e., for a PUT/POST operation + * with plenty of upload data) this allows the application + * to easily associate some request-specific state. + * If necessary, this state can be cleaned up in the + * global #MHD_RequestCompletedCallback (which + * can be set with the #MHD_OPTION_NOTIFY_COMPLETED). + * Initially, `*con_cls` will be NULL. + * @return #MHD_YES if the connection was handled successfully, + * #MHD_NO if the socket must be closed due to a serios + * error while handling the request + */ +static int +url_handler (void *cls, + struct MHD_Connection *connection, + const char *url, + const char *method, + const char *version, + const char *upload_data, + size_t *upload_data_size, + void **con_cls) +{ +#define URL_PRODUCTS "/products" +#define URL_CONTRACT "/contract" +#define URL_CHECKOUT "/checkout" +#define URL_HTTPTEST "/httptest" +#define URL_DOWNLOAD "/download" +#define STR_404_NOTFOUND "The requested resource is not found" + struct MHD_Response *resp; + int no_destroy; + unsigned int status; + + resp = NULL; + status = 404; + no_destroy = 0; + LOG_DEBUG ("request for URL `%s'\n", url); + + if (0 == strncasecmp (url, URL_PRODUCTS, sizeof (URL_PRODUCTS))) + { + /* parse for /contract */ + if (0 == strcmp (MHD_HTTP_METHOD_GET, method)) + { + resp = list_products_resp; + no_destroy = 1; + status = 200; + } + else + GNUNET_break (0); /* FIXME: implement for post */ + } + + if (0 == strncasecmp (url, URL_CONTRACT, sizeof (URL_CONTRACT))) + { + /* parse for /contract */ + if (0 == strcmp (MHD_HTTP_METHOD_GET, method)) + status = handle_get_contract (connection, &resp); + else + GNUNET_break (0); /* FIXME: implement for post */ + } + + if (0 == strncasecmp (url, URL_CHECKOUT, sizeof (URL_CHECKOUT))) + { + json_t *checkout_obj; + int ret; + /* parse for /checkout */ + ret = process_post_json (connection, + con_cls, + upload_data, + upload_data_size, + &checkout_obj); + if (GNUNET_SYSERR == ret) + return MHD_NO; + if (GNUNET_NO == ret) + return MHD_YES; + /* Handle the response in the request handler */ + ret = handle_checkout (connection, checkout_obj); + return ret; + } + + if (0 == strncasecmp (url, URL_HTTPTEST, sizeof (URL_HTTPTEST))) + { + static char page[]="\ +<!DOCTYPE html> \ +<html><title>HTTP Test page</title><body><center><h3>HTTP Test page</h3> \ +</center></body></html>"; + resp = MHD_create_response_from_buffer (sizeof (page) - 1, + page, + MHD_RESPMEM_PERSISTENT); + EXITIF (NULL == resp); + } + + if ((0 == strncasecmp (url, URL_DOWNLOAD, sizeof (URL_DOWNLOAD))) + && (0 == strcmp (MHD_HTTP_METHOD_GET, method))) + { + status = handle_download (connection, &resp); + if (status != MHD_HTTP_OK) + no_destroy = 1; + } + if (NULL != resp) + { + EXITIF (MHD_YES != MHD_queue_response (connection, status, resp)); + if (!no_destroy) + MHD_destroy_response (resp); + } + else + EXITIF (GNUNET_OK != failure_resp (connection, status)); + return MHD_YES; + + EXITIF_exit: + result = GNUNET_SYSERR; + GNUNET_SCHEDULER_shutdown (); + return MHD_NO; +} + + +/** + * Callback for catching serious error conditions from MHD. + * + * @param cls user specified value + * @param file where the error occured + * @param line where the error occured + * @param reason error detail, may be NULL + */ +static void +mhd_panic_cb (void *cls, + const char *file, + unsigned int line, + const char *reason) +{ + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "MHD panicked at %s:%u: %s", + file, line, reason); + result = GNUNET_SYSERR; + GNUNET_SCHEDULER_shutdown (); +} + +/** + * Function called with a filename. + * + * @param cls closure + * @param filename complete filename (absolute path) + * @return #GNUNET_OK to continue to iterate, + * #GNUNET_NO to stop iteration with no error, + * #GNUNET_SYSERR to abort iteration with error! + */ +static int +add_download_file (void *cls, const char *filename) +{ + struct Download *dwn; + + dwn = GNUNET_new (struct Download); + dwn->filename = GNUNET_strdup (filename); + dwn->id = ndownloads++; + GNUNET_CONTAINER_DLL_insert (dwn_head, dwn_tail, dwn); + return GNUNET_OK; +} + + +/** + * Function to build a MHD response object to list products + * + * @return GNUNET_OK upon success; GNUNET_SYSERR otherwise + */ +static int +build_list_product_response () +{ + const char *header = "\ +<!DOCTYPE html> \ +<html><title>Products List</title> \ +<body><center><ol>"; + char **partials; + const char *footer = "</ol></center></body></html>"; + char *page; + struct Download *dwn; + size_t size; + unsigned int cnt; + unsigned int psize; + unsigned int header_size; + unsigned int footer_size; + unsigned int *partial_sizes; + int ret; + + ret = GNUNET_SYSERR; + GNUNET_assert (NULL == list_products_resp); + header_size = strlen (header); + footer_size = strlen (footer); + size = header_size; + size += footer_size; + partials = GNUNET_malloc (sizeof (char *) * ndownloads); + partial_sizes = GNUNET_malloc (sizeof (unsigned int) * ndownloads); + EXITIF (0 == ndownloads); + for (cnt = 0, dwn = dwn_head; cnt < ndownloads; cnt++, dwn=dwn->next) + { + EXITIF (NULL == dwn); + psize = GNUNET_asprintf (&partials[cnt], + "<li><a href=\"/contract?product=%u\">%s</a></li>", + cnt, + GNUNET_STRINGS_get_short_name (dwn->filename)); + EXITIF (psize < 0); + size += psize; + partial_sizes [cnt] = psize; + } + page = GNUNET_malloc (size); + size = 0; + (void) memcpy (page, header, header_size); + size += header_size; + for (cnt = 0; cnt < ndownloads; cnt++) + { + (void) memcpy (page + size, partials[cnt], partial_sizes[cnt]); + size += partial_sizes[cnt]; + } + (void) memcpy (page + size, footer, footer_size); + size += footer_size; + list_products_resp = MHD_create_response_from_buffer (size, page, MHD_RESPMEM_MUST_FREE); + ret = GNUNET_OK; + + EXITIF_exit: + for (cnt = 0; cnt < ndownloads; cnt++) + GNUNET_free_non_null (partials[cnt]); + GNUNET_free_non_null (partials); + GNUNET_free_non_null (partial_sizes); + return ret; +} + +/** + * Main function that will be run by the scheduler. + * + * @param cls closure + * @param args remaining command-line arguments + * @param cfgfile name of the configuration file used (for saving, can be NULL!) + * @param config configuration + */ +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *config) +{ + char *keyfile; + struct MERCHANT_MintInfo *mint_infos; + unsigned int nmints; + unsigned int cnt; + + result = GNUNET_SYSERR; + keyfile = NULL; + mint_infos = NULL; + shutdown_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, + &do_shutdown, NULL); + if (NULL == data_dir) + { + LOG_ERROR ("Data directory for download files is missing. It can be given with the `-d' option\n"); + goto EXITIF_exit; + } + EXITIF (GNUNET_SYSERR == (nmints = TALER_MERCHANT_parse_mints (config, + &mint_infos))); + EXITIF (NULL == (wire = TALER_MERCHANT_parse_wireformat_sepa (config))); + EXITIF (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (config, + "merchant", + "KEYFILE", + &keyfile)); + EXITIF (NULL == (privkey = GNUNET_CRYPTO_eddsa_key_create_from_file (keyfile))); + EXITIF (0 == GNUNET_DISK_directory_scan (data_dir, + &add_download_file, + NULL)); + EXITIF (GNUNET_SYSERR == build_list_product_response ()); + EXITIF (NULL == (db_conn = MERCHANT_DB_connect (config))); + EXITIF (GNUNET_OK != MERCHANT_DB_initialise (db_conn, dry)); + EXITIF (GNUNET_SYSERR == + GNUNET_CONFIGURATION_get_value_number (config, + "merchant", + "port", + &port)); + EXITIF (GNUNET_SYSERR == + GNUNET_CONFIGURATION_get_value_string (config, + "merchant", + "hostname", + &hostname)); + EXITIF (NULL == (mctx = TALER_MINT_init ())); + EXITIF (NULL == (mints_map = GNUNET_CONTAINER_multipeermap_create (nmints, GNUNET_YES))); + for (cnt = 0; cnt < nmints; cnt++) + { + struct Mint *mint; + + mint = GNUNET_new (struct Mint); + mint->pubkey = mint_infos[cnt].pubkey; + mint->conn = TALER_MINT_connect (mctx, + mint_infos[cnt].hostname, + mint_infos[cnt].port, + &mint->pubkey); + EXITIF (NULL == mint->conn); + EXITIF (GNUNET_SYSERR == GNUNET_CONTAINER_multipeermap_put + (mints_map, + (struct GNUNET_PeerIdentity *) &mint->pubkey, + mint, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)); + } + MHD_set_panic_func (&mhd_panic_cb, NULL); + mhd = MHD_start_daemon (MHD_USE_DEBUG, //| MHD_USE_TCP_FASTOPEN, + (unsigned short) port, + NULL, NULL, + &url_handler, NULL, + //MHD_OPTION_TCP_FASTOPEN_QUEUE_SIZE, + //(unsigned int) 16, + MHD_OPTION_END); + EXITIF (NULL == mhd); + EXITIF (GNUNET_SYSERR == poll_mhd ()); + GNUNET_CRYPTO_hash (wire, sizeof (*wire), &h_wire); + result = GNUNET_OK; + + EXITIF_exit: + if (NULL != mint_infos) + { + for (cnt = 0; cnt < nmints; cnt++) + GNUNET_free (mint_infos[cnt].hostname); + GNUNET_free (mint_infos); + } + GNUNET_free_non_null (keyfile); + if (GNUNET_OK != result) + GNUNET_SCHEDULER_shutdown (); +} + + +/** + * The main function of the serve tool + * + * @param argc number of arguments from the command line + * @param argv command line arguments + * @return 0 ok, 1 on error + */ +int +main (int argc, char *const *argv) +{ + static const struct GNUNET_GETOPT_CommandLineOption options[] = { + {'t', "temp", NULL, + gettext_noop ("Use temporary database tables"), GNUNET_NO, + &GNUNET_GETOPT_set_one, &dry}, + {'d', "dir", "DIRECTORY", + gettext_noop ("Directory of the data files to serve"), GNUNET_YES, + &GNUNET_GETOPT_set_string, &data_dir}, + GNUNET_GETOPT_OPTION_END + }; + + if (GNUNET_OK != + GNUNET_PROGRAM_run (argc, argv, + "taler-merchant-serve", + "Serve merchant's HTTP interface", + options, &run, NULL)) + return 3; + return (GNUNET_OK == result) ? 0 : 1; +} diff --git a/src/merchant/test_merchant.c b/src/merchant/test_merchant.c new file mode 100644 index 00000000..bcec09ae --- /dev/null +++ b/src/merchant/test_merchant.c @@ -0,0 +1,96 @@ +/* + This file is part of TALER + (C) 2014 Christian Grothoff (and other contributing authors) + + TALER 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, or (at your option) any later version. + + TALER 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 + TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> +*/ + +/** + * @file merchant/test_merchant.c + * @brief File to test merchant-internal helper functions. + * @author Sree Harsha Totakura <sreeharsha@totakura.in> + */ + +#include "platform.h" +#include <gnunet/gnunet_util_lib.h> +#include "merchant.h" + +/** + * Array of parsed mints + */ +struct MERCHANT_MintInfo *mints; + +/** + * Number of mints in the above array + */ +int n_mints; + +/** + * Test result + */ +static int result; + +static void +do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + unsigned int cnt; + + for (cnt=0; cnt < n_mints; cnt++) + GNUNET_free (mints[cnt].hostname); + GNUNET_free_non_null (mints); + mints = 0; +} + + +/** + * Main function that will be run by the scheduler. + * + * @param cls closure + * @param args remaining command-line arguments + * @param cfgfile name of the configuration file used (for saving, can be NULL!) + * @param config configuration + */ +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *config) +{ + + mints = NULL; + n_mints = GNUNET_SYSERR; + n_mints = TALER_MERCHANT_parse_mints (config, &mints); + GNUNET_assert (GNUNET_SYSERR != n_mints); + GNUNET_assert (NULL != mints); + result = GNUNET_OK; + GNUNET_SCHEDULER_add_now (&do_shutdown, NULL); +} + +int +main (int argc, char *const argv[]) +{ + char *argv2[] = { + "test-merchant", + "-c", "test_merchant.conf", + NULL + }; + static const struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + + result = GNUNET_SYSERR; + if (GNUNET_OK != + GNUNET_PROGRAM_run ((sizeof (argv2) / sizeof (char *)) - 1, + argv2, "test-merchant", + "File to test merchant-internal helper functions.", + options, &run, NULL)) + return 3; + return (GNUNET_OK == result) ? 0 : 1; +} diff --git a/src/merchant/test_merchant.conf b/src/merchant/test_merchant.conf new file mode 100644 index 00000000..7d32769a --- /dev/null +++ b/src/merchant/test_merchant.conf @@ -0,0 +1,36 @@ +# Sample configuration file test-merchant testcase +[merchant] +PORT = 4251 +HOSTNAME = localhost +# List of mints the merchant trusts delimited by a single space +TRUSTED_MINTS = nayapaisa + +#nayapaisa nyadirahim + +# Our secret key file +KEYFILE = test_merchant.ecc + +[mint-taler] +HOSTNAME = localhost +PORT = 4241 +PUBKEY = 8MF3D4V40K4J7654Q7NT3YHZVJ22SJAMBG07GEQ0QSXHWF4M9X6G + +[mint-nayapaisa] +HOSTNAME = localhost +PORT = 4241 +# The public key of this mint +PUBKEY = 6ZE0HEY2M0FWP61M0470HYBF4K6RRD5DP54372PD2TN9N9VX2VJG + +[mint-nyadirahim] +HOSTNAME = nyadirahim.org +PORT = 4241 +# The public key of this mint +PUBKEY = 7995WKK71KPKTBBMA5BHNBSZFGNRZPYNXDJMQ8EK86V9598H03TG + +[merchant-db] +CONFIG = postgres:///taler + +[wire-sepa] +IBAN = DE67830654080004822650 +NAME = GNUNET E.V +BIC = GENODEF1SRL diff --git a/src/merchant/test_merchant.ecc b/src/merchant/test_merchant.ecc new file mode 100644 index 00000000..ac8ee6e9 --- /dev/null +++ b/src/merchant/test_merchant.ecc @@ -0,0 +1,2 @@ +MY{.ӂce +ف
\ No newline at end of file diff --git a/src/merchant/test_merchant_db.c b/src/merchant/test_merchant_db.c new file mode 100644 index 00000000..d3eca890 --- /dev/null +++ b/src/merchant/test_merchant_db.c @@ -0,0 +1,147 @@ +/* + This file is part of TALER + (C) 2014 Christian Grothoff (and other contributing authors) + + TALER 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, or (at your option) any later version. + + TALER 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 + TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> +*/ + +/** + * @file merchant/test_merchant_db.c + * @brief File to test merchant database helper functions. + * @author Sree Harsha Totakura <sreeharsha@totakura.in> + */ + +#include "platform.h" +#include <gnunet/gnunet_util_lib.h> +#include "taler_util.h" +#include "merchant_db.h" + +/** + * Shorthand for exit jumps. + */ +#define EXITIF(cond) \ + do { \ + if (cond) { GNUNET_break (0); goto EXITIF_exit; } \ + } while (0) + +/** + * Macro to round microseconds to seconds in GNUNET_TIME_* structs. + */ +#define ROUND_TO_SECS(name,us_field) name.us_field -= name.us_field % (1000 * 1000); + +/** + * The database handle + */ +PGconn *conn; + +/** + * Test result + */ +static int result; + +static void +do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + if (NULL != conn) + MERCHANT_DB_disconnect (conn); + conn = NULL; +} + + +/** + * Main function that will be run by the scheduler. + * + * @param cls closure + * @param args remaining command-line arguments + * @param cfgfile name of the configuration file used (for saving, can be NULL!) + * @param config configuration + */ +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *config) +{ + struct GNUNET_TIME_Absolute expiry; + struct TALER_Amount amount; + char *desc = "A contract from GNUnet e.V to say a big Thank You for a donation of the aforementioned amount."; + uint64_t nounce; + uint64_t product; + long long transaction_id; + + conn = MERCHANT_DB_connect (config); + EXITIF (NULL == conn); + GNUNET_SCHEDULER_add_now (&do_shutdown, NULL); + EXITIF (GNUNET_OK != MERCHANT_DB_initialise (conn, GNUNET_YES)); + expiry = GNUNET_TIME_absolute_get (); + expiry = GNUNET_TIME_absolute_add (expiry, GNUNET_TIME_UNIT_DAYS); + ROUND_TO_SECS (expiry, abs_value_us); + amount.value = 1; + amount.fraction = 0; + nounce = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_NONCE, UINT64_MAX); + product = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_NONCE, UINT64_MAX); + product &= (UINT64_MAX >> 1); + EXITIF (-1 == (transaction_id = MERCHANT_DB_contract_create (conn, + expiry, + &amount, + desc, + nounce, + product))); + { + struct GNUNET_CRYPTO_EddsaPublicKey coin_pub; + struct GNUNET_CRYPTO_EddsaSignature coin_sig; + long long paid_product; + + GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, + &coin_pub, sizeof (coin_pub)); + GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, + &coin_sig, sizeof (coin_sig)); + EXITIF (GNUNET_SYSERR == MERCHANT_DB_checkout_create (conn, + &coin_pub, + transaction_id, + &amount, + &coin_sig)); + EXITIF (-1 == (paid_product = MERCHANT_DB_get_checkout_product (conn, + &coin_pub))); + EXITIF (paid_product < 0); + EXITIF (((uint64_t) paid_product) != product); + /* We should get -1 for product if a coin is not paid to us */ + GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, + &coin_pub, sizeof (coin_pub)); + EXITIF (-1 != (product = MERCHANT_DB_get_checkout_product (conn, + &coin_pub))); + } + result = GNUNET_OK; + + EXITIF_exit: + return; +} + +int +main (int argc, char *const argv[]) +{ + char *argv2[] = { + "test-merchant-db", + "-c", "test_merchant.conf", + NULL + }; + static const struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + + result = GNUNET_SYSERR; + if (GNUNET_OK != + GNUNET_PROGRAM_run ((sizeof (argv2) / sizeof (char *)) - 1, + argv2, "test-merchant-db", + "File to test merchant database helper functions.", + options, &run, NULL)) + return 3; + return (GNUNET_OK == result) ? 0 : 1; +} |