From 6fe47cca8594e3b75e51e99de22a308a758862c9 Mon Sep 17 00:00:00 2001 From: Patrick Bogen Date: Tue, 9 Dec 2014 12:30:55 -0800 Subject: [PATCH 01/10] Refactor of asksource/config process so that variable defs are written to Server/src/make.defs, which is included in MAkefile; and similarly for Server/src/do_compile.sh. This increases the reliability of the asksource.sh config process by not needing to do in-file pattern replacement with sed. --- Server/bin/asksource.sh | 79 ++++++++++++---------------------------- Server/src/Makefile | 29 +++++---------- Server/src/do_compile.sh | 8 +++- 3 files changed, 39 insertions(+), 77 deletions(-) diff --git a/Server/bin/asksource.sh b/Server/bin/asksource.sh index 113c55e0d..00ed607dc 100755 --- a/Server/bin/asksource.sh +++ b/Server/bin/asksource.sh @@ -1293,7 +1293,6 @@ setdefaults() { DEFS="${DEFS} -DHAS_OPENSSL" fi fi - DEFS="DEFS = ${DEFS}" } ################################################################### @@ -1463,92 +1462,60 @@ setlibs() { echo "Compiling with system pcre library..." MORELIBS="${MORELIBS} -lpcre" fi - MORELIBS="MORELIBS = ${MORELIBS}" } ################################################################### # UPDATEMAKEFILE - Update the makefile with the changes ################################################################### updatemakefile() { - echo "Updating the DEFS section of the Makefile now. Please wait..." - cat ../src/Makefile|sed "s/$(grep ^DEF ../src/Makefile|sed "s/\//\\\\\//g")/${DEFS}/g" > /tmp/$$CONF$$ - mv -f ../src/Makefile ../src/Makefile.${DATE} 2>/dev/null - mv -f /tmp/$$CONF$$ ../src/Makefile 2>/dev/null - rm -f /tmp/$$CONF$$ 2>/dev/null + echo 'Updating the DEFS section of the Makefile now. Please wait...' + echo "DEFS = ${DEFS}" > ../src/make.defs -# Let's do the door additions here - if [ "${XB[2]}" = "X" ] + echo '# Begin Door Configurations' >> ../src/make.defs + if [ "${XB[2]}" = 'X' ] then - cat ../src/Makefile|sed "s/^#DR_DEF/DR_DEF/g" > /tmp/$$CONF$$ - mv -f /tmp/$$CONF$$ ../src/Makefile 2>/dev/null - rm -f /tmp/$$CONF$$ 2>/dev/null + echo 'DR_DEF = -DENABLE_DOORS -DEXAMPLE_DOOR_CODE' >> ../src/make.defs if [ "${XD[1]}" = "X" ] then - cat ../src/Makefile|sed "s/^#DRMUSH/DRMUSH/g" > /tmp/$$CONF$$ - else - cat ../src/Makefile|sed "s/^DRMUSH/#DRMUSH/g" > /tmp/$$CONF$$ + echo 'DRMUSHSRC = door_mush.c' >> ../src/make.defs + echo 'DRMUSHOBJ = door_mush.o' >> ../src/make.defs fi - mv -f /tmp/$$CONF$$ ../src/Makefile 2>/dev/null - rm -f /tmp/$$CONF$$ 2>/dev/null if [ "${XD[2]}" = "X" ] then - cat ../src/Makefile|sed "s/^#DREMPIRE/DREMPIRE/g"|sed "s/^#DR_HDR/DR_HDR/g" > /tmp/$$CONF$$ - else - cat ../src/Makefile|sed "s/^DREMPIRE/#DREMPIRE/g"|sed "s/^DR_HDR/#DR_HDR/g" > /tmp/$$CONF$$ + echo 'DREMPIRESRC = empire.c' >> ../src/make.defs + echo 'DREMPIREOBJ = empire.o' >> ../src/make.defs + echo 'DREMPIREHDR = empire.h' >> ../src/make.defs fi - mv -f /tmp/$$CONF$$ ../src/Makefile 2>/dev/null - rm -f /tmp/$$CONF$$ 2>/dev/null if [ "${XD[3]}" = "X" ] then - cat ../src/Makefile|sed "s/^#DRMAIL/DRMAIL/g" > /tmp/$$CONF$$ - else - cat ../src/Makefile|sed "s/^DRMAIL/#DRMAIL/g" > /tmp/$$CONF$$ + echo 'DRMAILSRC = door_mail.c' >> ../src/make.defs + echo 'DRMAILOBJ = door_mail.o' >> ../src/make.defs fi - mv -f /tmp/$$CONF$$ ../src/Makefile 2>/dev/null - rm -f /tmp/$$CONF$$ 2>/dev/null - else - cat ../src/Makefile|sed "s/^DR_DEF/#DR_DEF/g"|sed "s/^DRMUSH/#DRMUSH/g"| \ - sed "s/^DREMPIRE/#DREMPIRE/g"|sed "s/^DRMAIL/#DRMAIL/g" > /tmp/$$CONF$$ - mv -f /tmp/$$CONF$$ ../src/Makefile 2>/dev/null - rm -f /tmp/$$CONF$$ 2>/dev/null fi + echo '# End Door Configurations' >> ../src/make.defs + if [ "${XB[5]}" = "X" ] then echo "Compiling to QDBM database." - sed "s~^$(grep "^LIBS " ../src/Makefile)~LIBS = -L./qdbm/ -lqdbm~g" ../src/Makefile > /tmp/$$CONF$$ - mv -f /tmp/$$CONF$$ ../src/Makefile - rm -f /tmp/$$CONF$$ - sed "s~^$(grep "^COMP=" ../src/do_compile.sh)~COMP=qdbm~g" ../src/do_compile.sh > /tmp/$$CONF$$ - mv -f /tmp/$$CONF$$ ../src/do_compile.sh - chmod 755 ../src/do_compile.sh - rm -f /tmp/$$CONF$$ + echo '# Use QDBM. See also do_compile.defs' >> ../src/make.defs + echo 'LIBS = -L./qdbm/ -lqdbm' >> ../src/make.defs + echo 'COMP=qdbm' > ../src/do_compile.defs else echo "Compiling to GDBM database (default)." - sed "s~^$(grep "^LIBS " ../src/Makefile)~LIBS = -L./gdbm-1.8.3/.libs/ -lgdbm_compat -L./gdbm-1.8.3/ -lgdbm~g" ../src/Makefile > /tmp/$$CONF$$ - mv -f /tmp/$$CONF$$ ../src/Makefile - rm -f /tmp/$$CONF$$ - sed "s~^$(grep "^COMP=" ../src/do_compile.sh)~COMP=gdbm~g" ../src/do_compile.sh > /tmp/$$CONF$$ - mv -f /tmp/$$CONF$$ ../src/do_compile.sh - chmod 755 ../src/do_compile.sh - rm -f /tmp/$$CONF$$ + echo '# Use (default) GDBM. See also do_compile.defs' >> ../src/make.defs + echo 'LIBS = -L./gdbm-1.8.3/.libs/ -lgdbm_compat -L./gdbm-1.8.3/ -lgdbm' >> ../src/make.defs + echo 'COMP=gdbm' > ../src/do_compile.defs fi # add CFLAGS for low memory if [ "${X[23]}" = "X" ] then echo "Adding CFLAG option for low memory compile..." - cat ../src/Makefile|sed "s/^#CFLAG/CFLAG/g" > /tmp/$$CONF$$ - else - cat ../src/Makefile|sed "s/^CFLAG/#CFLAG/g" > /tmp/$$CONF$$ + echo '# Low-memory compile' >> ../src/make.defs + echo 'CFLAGS = --param ggc-min-expand=0 --param ggc-min-heapsize=8192' >> ../src/make.defs fi - mv -f /tmp/$$CONF$$ ../src/Makefile 2>/dev/null - rm -f /tmp/$$CONF$$ 2>/dev/null echo "...completed." echo "Updating the MORELIBS section of the Makefile now. Please wait..." - cat ../src/Makefile|sed "s/$(grep ^MORELIBS ../src/Makefile| \ - sed "s/\//\\\\\//g")/${MORELIBS}/g" > /tmp/$$CONF$$ - mv -f ../src/Makefile ../src/Makefile.${DATE} 2>/dev/null - mv -f /tmp/$$CONF$$ ../src/Makefile 2>/dev/null - rm -f /tmp/$$CONF$$ 2>/dev/null + echo "MORELIBS = ${MORELIBS}" >> ../src/make.defs echo "...completed." } diff --git a/Server/src/Makefile b/Server/src/Makefile index 9fcad563d..e5e9e1cc1 100644 --- a/Server/src/Makefile +++ b/Server/src/Makefile @@ -4,6 +4,8 @@ # Search for the text 'CONFIGURATION SECTION' and make any changes needed # there. +include make.defs + SHELL=/bin/sh srcdir = . bindir = ../bin @@ -17,13 +19,12 @@ else endif # CPP = gcc -E # This is broken in autoconf. Sigh. CPP = $(CC) -E -# Sometime, LIBS won't allow '-lndbm' here. If so, remove it. -# If using CYGWIN, comment out the whole line. -LIBS = -L./gdbm-1.8.3/.libs/ -lgdbm_compat -L./gdbm-1.8.3/ -lgdbm -#LIBS = -L./qdbm/ -lqdbm + +# LIBS is now written to make.defs by asksource.sh + LIBOBJS = -# for compiling on lowmem systems use this -#CFLAGS = --param ggc-min-expand=0 --param ggc-min-heapsize=8192 + +# CFLAGS (used only to enable low-mem compile) is now written to make.defs by asksource.sh # If you wish to debug the code, run under this OPTIM = -g @@ -47,18 +48,10 @@ UDB_INC = udb.h udb_defs.h COM_SRC = COM_OBJ = -# Door Configurations -#DRMUSHSRC = door_mush.c -#DRMUSHOBJ = door_mush.o -#DREMPIRESRC = empire.c -#DREMPIREOBJ = empire.o -#DREMPIREHDR = empire.h -#DRMAILSRC = door_mail.c -#DRMAILOBJ = door_mail.o +# Door Configurations -- "Options" now written to make.defs by asksource.sh DR_SRC = $(DRMUSHSRC) $(DREMPIRESRC) $(DRMAILSRC) DR_OBJ = $(DRMUSHOBJ) $(DREMPIREOBJ) $(DRMAILOBJ) DR_HDR = $(DREMPIREHDR) -#DR_DEF = -DENABLE_DOORS -DEXAMPLE_DOOR_CODE # Everything needed to use the database in standalone mode. SA_SRC = sa-db.c sa-db_rw.c sa-boolexp.c sa-unparse.c sa-compress.c \ @@ -156,7 +149,6 @@ VER_FLG = -DMUSH_BUILD_DATE="\"`cat date.txt`\"" \ # SYS_MALLOC - Used if malloc.h is in a borked spot. ########################################################################################################### -DEFS = -DBROKEN_NDBM -DBROKEN_ERRNO_SYS -DSQLITE -DSBUF64 -DSECURE_SIDEEFFECT -DOLD_SETQ -DBANGS -DMARKER_FLAGS -DZENTY_ANSI -DEXPANDED_QREGS -DREALITY_LEVELS -DATTR_HACK -DPROG_LIKEMUX -DPLUSHELP -DUSECRYPT -DSOFTCOM -DMUX_INCDEC -DTINY_U -DUSE_SIDEEFFECT -Wall -DHAS_OPENSSL # # Rhost supports two encryption schemes SHS (SHA-1), and the # unix crypt() function (DES). @@ -212,7 +204,8 @@ DEFS = -DBROKEN_NDBM -DBROKEN_ERRNO_SYS -DSQLITE -DSBUF64 -DSECURE_SIDEEFFECT -D # #CYGWIN = -I/usr/local/include -DCYGWIN -DBROKEN_ERRNO_SYS -DBROKEN_NDBM\ # -DSYSWAIT -DNODEBUGMONITOR -g - + +# IMPORTANT: MORELIBS is now written to make.defs by asksource.sh # Libraries. # The following extra libraries are required based on what system you have. # #1 - This is used for most libc5 distributions. This includes Slackware 7.0 @@ -242,8 +235,6 @@ DEFS = -DBROKEN_NDBM -DBROKEN_ERRNO_SYS -DSQLITE -DSBUF64 -DSECURE_SIDEEFFECT -D ################################################################ #5 #MORELIBS = -lm -lrt -L/usr/local/lib -lcygipc -MORELIBS = -lm -lrt -lnsl -lresolv -lcrypt -lssl - # Set this to the directory where the MUSH game lives. # This is not really used much GAME = /usr/games/lib/mush diff --git a/Server/src/do_compile.sh b/Server/src/do_compile.sh index 779a3f8b3..ddd3914ad 100755 --- a/Server/src/do_compile.sh +++ b/Server/src/do_compile.sh @@ -1,7 +1,11 @@ #!/bin/sh # -COMP=gdbm -case ${COMP} in + +[ -f ../src/do_compile.defs ] && . ../src/do_compile.defs + +# ${COMP:=gdbm} uses COMP or, if COMP is unset, sets COMP to gdbm and uses gdbm + +case ${COMP:=gdbm} in gdbm) gdbmdir=./gdbm-1.8.3 ;; qdbm) gdbmdir=./qdbm From 3d1473246d8e8cf69ed7eb9b0ed25be9f3955c4d Mon Sep 17 00:00:00 2001 From: Patrick Bogen Date: Fri, 30 Jan 2015 11:05:54 -0800 Subject: [PATCH 02/10] use single-quotes to prevent shell interpretation of $! etc. in bang-notation description --- Server/bin/asksource.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Server/bin/asksource.sh b/Server/bin/asksource.sh index 00ed607dc..cff8881c6 100755 --- a/Server/bin/asksource.sh +++ b/Server/bin/asksource.sh @@ -421,11 +421,11 @@ info() { echo "flags, are essentially 'markers' that you can rename at leasure." echo "If you have a desire for marker flags, enable this option." ;; - 15) echo "Bang support. Very cool stuff. It allows you to use ! for false" - echo "and !! for true. An example would be [!match(this,that)]. It" - echo "also allows $! for 'not a string' and $!! for 'is a string'." - echo "Such an example would be [$!get(me/blah)]. If you like this" - echo "feature, enable this option. You want it. Really." + 15) echo 'Bang support. Very cool stuff. It allows you to use ! for false' + echo 'and !! for true. An example would be [!match(this,that)]. It' + echo 'also allows $! for "not a string" and $!! for "is a string".' + echo 'Such an example would be [$!get(me/blah)]. If you like this' + echo 'feature, enable this option. You want it. Really.' ;; 16) echo "This is an alternate WHO listing. It's a tad longer for the" echo "display and will switch ports to Total Cmds on the WHO listings." From 50ced5b1c30666f7535bdaf14bfe8ba0c668adce Mon Sep 17 00:00:00 2001 From: Patrick Bogen Date: Fri, 30 Jan 2015 11:10:32 -0800 Subject: [PATCH 03/10] More reliably locate destination for make.defs and do_compile.defs --- Server/bin/asksource.sh | 53 +++++++++++++++++++++++++---------------- 1 file changed, 33 insertions(+), 20 deletions(-) diff --git a/Server/bin/asksource.sh b/Server/bin/asksource.sh index cff8881c6..3e231e4ce 100755 --- a/Server/bin/asksource.sh +++ b/Server/bin/asksource.sh @@ -1468,54 +1468,67 @@ setlibs() { # UPDATEMAKEFILE - Update the makefile with the changes ################################################################### updatemakefile() { + makedefs_path="" + for p in src/ ../src ../../src; do + if [ -d $p -a -e $p/Makefile ]; then + makedefs_path=$p/make.defs + compiledefs_path=$p/do_compile.defs + break + fi + done + if [ "z$makedefs_path" = "z" ] + then + echo '$0: error: could not locate Makefile, cannot determine where to generate make.defs' >&2 + exit 1 + fi echo 'Updating the DEFS section of the Makefile now. Please wait...' - echo "DEFS = ${DEFS}" > ../src/make.defs + echo "DEFS = ${DEFS}" > $makedefs_path - echo '# Begin Door Configurations' >> ../src/make.defs + echo '# Begin Door Configurations' >> $makedefs_path if [ "${XB[2]}" = 'X' ] then - echo 'DR_DEF = -DENABLE_DOORS -DEXAMPLE_DOOR_CODE' >> ../src/make.defs + echo 'DR_DEF = -DENABLE_DOORS -DEXAMPLE_DOOR_CODE' >> $makedefs_path if [ "${XD[1]}" = "X" ] then - echo 'DRMUSHSRC = door_mush.c' >> ../src/make.defs - echo 'DRMUSHOBJ = door_mush.o' >> ../src/make.defs + echo 'DRMUSHSRC = door_mush.c' >> $makedefs_path + echo 'DRMUSHOBJ = door_mush.o' >> $makedefs_path fi if [ "${XD[2]}" = "X" ] then - echo 'DREMPIRESRC = empire.c' >> ../src/make.defs - echo 'DREMPIREOBJ = empire.o' >> ../src/make.defs - echo 'DREMPIREHDR = empire.h' >> ../src/make.defs + echo 'DREMPIRESRC = empire.c' >> $makedefs_path + echo 'DREMPIREOBJ = empire.o' >> $makedefs_path + echo 'DREMPIREHDR = empire.h' >> $makedefs_path fi if [ "${XD[3]}" = "X" ] then - echo 'DRMAILSRC = door_mail.c' >> ../src/make.defs - echo 'DRMAILOBJ = door_mail.o' >> ../src/make.defs + echo 'DRMAILSRC = door_mail.c' >> $makedefs_path + echo 'DRMAILOBJ = door_mail.o' >> $makedefs_path fi fi - echo '# End Door Configurations' >> ../src/make.defs + echo '# End Door Configurations' >> $makedefs_path if [ "${XB[5]}" = "X" ] then echo "Compiling to QDBM database." - echo '# Use QDBM. See also do_compile.defs' >> ../src/make.defs - echo 'LIBS = -L./qdbm/ -lqdbm' >> ../src/make.defs - echo 'COMP=qdbm' > ../src/do_compile.defs + echo '# Use QDBM. See also do_compile.defs' >> $makedefs_path + echo 'LIBS = -L./qdbm/ -lqdbm' >> $makedefs_path + echo 'COMP=qdbm' > $compiledefs_path else echo "Compiling to GDBM database (default)." - echo '# Use (default) GDBM. See also do_compile.defs' >> ../src/make.defs - echo 'LIBS = -L./gdbm-1.8.3/.libs/ -lgdbm_compat -L./gdbm-1.8.3/ -lgdbm' >> ../src/make.defs - echo 'COMP=gdbm' > ../src/do_compile.defs + echo '# Use (default) GDBM. See also do_compile.defs' >> $makedefs_path + echo 'LIBS = -L./gdbm-1.8.3/.libs/ -lgdbm_compat -L./gdbm-1.8.3/ -lgdbm' >> $makedefs_path + echo 'COMP=gdbm' > $compiledefs_path fi # add CFLAGS for low memory if [ "${X[23]}" = "X" ] then echo "Adding CFLAG option for low memory compile..." - echo '# Low-memory compile' >> ../src/make.defs - echo 'CFLAGS = --param ggc-min-expand=0 --param ggc-min-heapsize=8192' >> ../src/make.defs + echo '# Low-memory compile' >> $makedefs_path + echo 'CFLAGS = --param ggc-min-expand=0 --param ggc-min-heapsize=8192' >> $makedefs_path fi echo "...completed." echo "Updating the MORELIBS section of the Makefile now. Please wait..." - echo "MORELIBS = ${MORELIBS}" >> ../src/make.defs + echo "MORELIBS = ${MORELIBS}" >> $makedefs_path echo "...completed." } From a5f8f0744cba7517b96500415367eeff3417f725 Mon Sep 17 00:00:00 2001 From: Patrick Bogen Date: Fri, 30 Jan 2015 11:53:40 -0800 Subject: [PATCH 04/10] Add support for bulding in libcurl; definitions and libraries, right now --- Server/bin/asksource.sh | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/Server/bin/asksource.sh b/Server/bin/asksource.sh index 3e231e4ce..0ac3d3f96 100755 --- a/Server/bin/asksource.sh +++ b/Server/bin/asksource.sh @@ -52,7 +52,7 @@ DATE="$(date +"%m%d%y")" MORELIBS="-lrt" OPTIONS="1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25" C_OPTIONS=$(echo $OPTIONS|wc -w) -BOPTIONS="1 2 3 4 5 6" +BOPTIONS="1 2 3 4 5 6 7" C_BOPTIONS=$(echo $BOPTIONS|wc -w) DOPTIONS="1 2 3" C_DOPTIONS=$(echo $DOPTIONS|wc -w) @@ -122,6 +122,7 @@ DEFB[2]="\$(DR_DEF)" DEFB[3]="-DSBUF64" DEFB[4]="-DSQLITE" DEFB[5]="-DQDBM" +DEFB[7]="-DCURL" DEFD[1]="-DMUSH_DOORS" DEFD[2]="-DEMPIRE_DOORS" @@ -211,6 +212,7 @@ echo "[${X[25]}] 25. Pcre System Libs" echo "--------------------------- Beta/Unsupported Additions -----------------------" echo "[${XB[1]}] B1. 3rd Party MySQL [${XB[2]}] B2. Door Support(Menu) [${XB[3]}] B3. 64 Char attribs" echo "[${XB[4]}] B4. SQLite Support [${XB[5]}] B5. QDBM DB Support [#] B6. LBUF Settings (Menu)" +echo "[${XB[7]}] B7. libcurl Support" echo "------------------------------------------------------------------------------" echo "" echo "Keys: [h]elp [i]nfo [s]ave [l]oad [d]elete [c]lear [m]ark [b]rowse [r]un [q]uit" @@ -384,9 +386,15 @@ info() { echo "if you wish to use them." fi ;; - 7) echo "RhostMUSH allows you to use a plushelp.txt file for +help. This" - echo "supports MUX/TinyMUSH3 in how +help is hardcoded to a text file." - echo "Enable this if you wish to have a plushelp.txt file be used." + 7) if [ $RUNBETA -eq 1 ] + then + echo "Enable libcurl support, to allow the use of http_get, http_post," + echo "and http_request from within RhostMUSH" + else + echo "RhostMUSH allows you to use a plushelp.txt file for +help. This" + echo "supports MUX/TinyMUSH3 in how +help is hardcoded to a text file." + echo "Enable this if you wish to have a plushelp.txt file be used." + fi ;; 8) echo "RhostMUSH, by default, allows multiple arguments to be passed" echo "to @program. This, unfortunately, is not how MUX does it, so" @@ -1262,6 +1270,14 @@ setdefaults() { MORELIBS="-lsqlite3 ${MORELIBS}" fi fi + + # Add definitions for libcurl + if [ "${XB[7]}" = "X" ] + then + echo "Patching curl libs with curl-config..." + MORELIBS="$(curl-config --libs) ${MORELIBS}" + fi + BOB1=$(uname -r|cut -f1 -d".") BOB2=$(uname -s) if [ -d /usr/ucbinclude -a "${BOB2}" = "SunOS" ] From cb9ba4050b7945599cfe1521c1187441b5c48e80 Mon Sep 17 00:00:00 2001 From: Patrick Bogen Date: Fri, 30 Jan 2015 13:01:16 -0800 Subject: [PATCH 05/10] Minimum viable libcurl bindings --- Server/bin/asksource.sh | 2 +- Server/hdrs/mudconf.h | 5 +- Server/src/Makefile | 4 +- Server/src/conf.c | 10 ++- Server/src/curl.c | 143 ++++++++++++++++++++++++++++++++++++++++ Server/src/local.c | 6 ++ 6 files changed, 165 insertions(+), 5 deletions(-) create mode 100644 Server/src/curl.c diff --git a/Server/bin/asksource.sh b/Server/bin/asksource.sh index 0ac3d3f96..ee249243c 100755 --- a/Server/bin/asksource.sh +++ b/Server/bin/asksource.sh @@ -122,7 +122,7 @@ DEFB[2]="\$(DR_DEF)" DEFB[3]="-DSBUF64" DEFB[4]="-DSQLITE" DEFB[5]="-DQDBM" -DEFB[7]="-DCURL" +DEFB[7]="-DRHOST_CURL" DEFD[1]="-DMUSH_DOORS" DEFD[2]="-DEMPIRE_DOORS" diff --git a/Server/hdrs/mudconf.h b/Server/hdrs/mudconf.h index 2f67930dc..fc7154fb3 100644 --- a/Server/hdrs/mudconf.h +++ b/Server/hdrs/mudconf.h @@ -427,7 +427,10 @@ struct confdata { int sqlite_query_limit; char sqlite_db_path[128]; #endif /* SQLITE */ -#else +#ifdef RHOST_CURL + int curl_request_limit; +#endif /* RHOST_CURL */ +#else /* STANDALONE */ int paylimit; /* getting money gets hard over this much */ int digcost; /* cost of @dig command */ int opencost; /* cost of @open command */ diff --git a/Server/src/Makefile b/Server/src/Makefile index e5e9e1cc1..695dcbab4 100644 --- a/Server/src/Makefile +++ b/Server/src/Makefile @@ -71,7 +71,7 @@ D_SRC = door.c shs.c mushcrypt.c news.c mail.c mailfix.c debug.c senses.c \ db.c db_rw.c compress.c stringutil.c object.c conf.c flags.c htab.c \ compat.c file_c.c player_c.c bsd.c alloc.c autoreg.c levels.c \ local.c utils.c pcre.c pcre_extensions.c tprintf.c sha1.c 64btime.c \ - sqlite.c $(DR_SRC) + sqlite.c curl.c $(DR_SRC) D_OBJ = door.o shs.o mushcrypt.o news.o mail.o mailfix.o debug.o senses.o \ create.o game.o help.o look.o match.o move.o player.o predicates.o \ @@ -80,7 +80,7 @@ D_OBJ = door.o shs.o mushcrypt.o news.o mail.o mailfix.o debug.o senses.o \ db.o db_rw.o compress.o stringutil.o object.o conf.o flags.o htab.o \ compat.o file_c.o player_c.o bsd.o alloc.o autoreg.o levels.o \ local.o utils.o pcre.o pcre_extensions.o tprintf.o sha1.o 64btime.o \ - sqlite.o $(DR_OBJ) + sqlite.o curl.o $(DR_OBJ) D_INC = door.h shs.h news.h mail.h debug.h \ copyright.h flags.h help.h htab.h interface.h match.h functions.h \ diff --git a/Server/src/conf.c b/Server/src/conf.c index 74a934412..b8b5b8e87 100644 --- a/Server/src/conf.c +++ b/Server/src/conf.c @@ -612,7 +612,9 @@ NDECL(cf_init) mudconf.sqlite_query_limit = 5; strcpy( mudconf.sqlite_db_path, "sqlite" ); #endif /* SQLITE */ - +#ifdef RHOST_CURL + mudconf.curl_request_limit = 5; +#endif /* RHOST_CURL */ /* maximum logs allowed per command */ mudconf.log_maximum = 1; mudconf.cluster_cap = 10; /* Cap of cluster wait in seconds for action */ @@ -4586,6 +4588,12 @@ CONF conftable[] = cf_bool, CA_GOD | CA_IMMORTAL, &mudconf.round_kludge, 0, 0, CA_PUBLIC, (char *) "Kludgy fix for rounding even numbers.\r\n"\ " Default: 0 Value: %d"}, /* [Loki] */ +#ifdef RHOST_CURL + {(char *) "curl_request_limit", + cf_int, CA_GOD | CA_IMMORTAL, &mudconf.curl_request_limit, 0, 0, CA_WIZARD, + (char *) "Maximum time in seconds that a libcurl request may run.\r\n"\ + " Default: 5 Value: %d"}, +#endif /*RHOST_CURL*/ #ifdef SQLITE {(char *) "sqlite_query_limit", cf_int, CA_GOD | CA_IMMORTAL, &mudconf.sqlite_query_limit, 0, 0, CA_WIZARD, diff --git a/Server/src/curl.c b/Server/src/curl.c new file mode 100644 index 000000000..babdb7121 --- /dev/null +++ b/Server/src/curl.c @@ -0,0 +1,143 @@ +#ifdef RHOST_CURL + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "copyright.h" +#include "autoconf.h" + +#include "config.h" +#include "db.h" +#include "interface.h" +#include "mudconf.h" +#include "command.h" +#include "functions.h" +#include "externs.h" +#include "match.h" +#include "flags.h" +#include "alloc.h" +#include "vattr.h" + + +FUNCTION(local_fun_curl_get); +static size_t write_callback( void * contents, size_t size, size_t nmemb, void *userp ); + +char tempbuff[LBUF_SIZE]; +char tempbuff2[LBUF_SIZE]; +regex_t curl_has_protocol, curl_valid_url; +uint8_t overflow = 0; + +static int ival(char *buff, char **bufcx, int result) { + sprintf(tempbuff, "%d", result); + safe_str(tempbuff, buff, bufcx); + return 0; +} + +void local_curl_init() { + FUN *fp; + char *buff, *cp, *dp; + + regcomp( &curl_has_protocol, ".*://.*", REG_EXTENDED | REG_NOSUB ); + regcomp( &curl_valid_url, "^(https?)://.*", REG_EXTENDED | REG_NOSUB ); + + static FUN fun_table[] = { + {"CURL_GET", local_fun_curl_get, 0, FN_VARARGS, CA_WIZARD, 0 }, + {NULL, NULL, 0, 0, 0, 0} + }; + +/* Register the functions */ + buff = alloc_sbuf("init_curl_functab"); + for (fp = fun_table ; fp->name ; fp++) { + cp = (char *) fp->name; + dp = buff; + while (*cp) { + *dp = ToLower(*cp); + cp++; + dp++; + } + *dp = '\0'; + hashadd2(buff, (int *) fp, &mudstate.func_htab, 1); + } +} + +FUNCTION(local_fun_curl_get) +{ + CURL * curl = NULL; + CURLcode result; + + if( nfargs < 1 ) { + safe_str( "#-1 CURL_GET EXPECTS 1 ARGUMENT [RECEIVED ", buff, bufcx ); + ival( buff, bufcx, nfargs ); + safe_str( "]", buff, bufcx ); + return; + } + + if( curl == NULL ) + curl = curl_easy_init(); + if( !curl ) { + STARTLOG(LOG_ALWAYS, "CURL", "FAIL") + log_text( "an error occurred initializing the cURL agent" ); + ENDLOG + safe_str( "#-1 INTERNAL ERROR", buff, bufcx ); + return; + } + + if( regexec( &curl_has_protocol, fargs[0], 0, NULL, 0 ) == 0 ) { + // Requested URL includes a protocol + snprintf( tempbuff, LBUF_SIZE, "%s", fargs[0] ); + } else { + // Requested URL does not include a protocol, assume http:// + snprintf( tempbuff, LBUF_SIZE, "http://%s", fargs[0] ); + } + + if( regexec( &curl_valid_url, tempbuff, 0, NULL, 0 ) != 0 ) { + safe_str( "#-1 ONLY HTTP:// AND HTTPS:// ALLOWED [RECEIVED ", buff, bufcx ); + safe_str( tempbuff, buff, bufcx ); + safe_str( "]", buff, bufcx ); + curl_easy_cleanup( curl ); + return; + } + + curl_easy_setopt( curl, CURLOPT_URL, tempbuff ); + curl_easy_setopt( curl, CURLOPT_FOLLOWLOCATION, 1L ); + + curl_easy_setopt( curl, CURLOPT_WRITEFUNCTION, write_callback ); + curl_easy_setopt( curl, CURLOPT_TIMEOUT, mudconf.curl_request_limit ); + + // truncate tempbuff2; this will hold our returned data + tempbuff2[0] = '\0'; + overflow = 0; + result = curl_easy_perform( curl ); + if( result != CURLE_OK ) { + if( overflow == 1 ) { + strncpy( tempbuff, tempbuff2, LBUF_SIZE ); + } else { + snprintf( tempbuff, LBUF_SIZE, "#-2 GET FAILED: %s", curl_easy_strerror( result ) ); + } + safe_str( tempbuff, buff, bufcx ); + } + + curl_easy_cleanup( curl ); +} + +static size_t write_callback( void * contents, size_t size, size_t nmemb, void *userp ) { + size_t realsize = size * nmemb; + size_t bytesleft = LBUF_SIZE - strnlen( tempbuff2, LBUF_SIZE ) - 1; + if( realsize < bytesleft ) { + strncat( tempbuff2, contents, realsize ); + return realsize; + } else { + strncat( tempbuff2, contents, bytesleft ); + overflow = 1; + return bytesleft; + } +} + +#endif diff --git a/Server/src/local.c b/Server/src/local.c index 8a1c711ab..57123d53f 100644 --- a/Server/src/local.c +++ b/Server/src/local.c @@ -26,11 +26,17 @@ #ifdef SQLITE extern void local_sqlite_init(void); #endif /* SQLITE */ +#ifdef RHOST_CURL + extern void local_curl_init(void); +#endif /* RHOST_CURL */ void local_startup(void) { #ifdef SQLITE local_sqlite_init(); #endif /* SQLITE */ +#ifdef RHOST_CURL + local_curl_init(); +#endif /* RHOST_CURL */ load_regexp_functions(); } From 85f402142a242578014d99db4227fc8b5afc6e59 Mon Sep 17 00:00:00 2001 From: Patrick Bogen Date: Fri, 30 Jan 2015 14:13:28 -0800 Subject: [PATCH 06/10] Send output even if it did not try to overflow the buffer. Lelz. --- Server/src/curl.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Server/src/curl.c b/Server/src/curl.c index babdb7121..cdf51d929 100644 --- a/Server/src/curl.c +++ b/Server/src/curl.c @@ -115,7 +115,9 @@ FUNCTION(local_fun_curl_get) tempbuff2[0] = '\0'; overflow = 0; result = curl_easy_perform( curl ); - if( result != CURLE_OK ) { + if( result == CURLE_OK ) { + safe_str( tempbuff2, buff, bufcx ); + } else { if( overflow == 1 ) { strncpy( tempbuff, tempbuff2, LBUF_SIZE ); } else { From 5552c2c6248a4e403f5a945b8326a0679595b2d5 Mon Sep 17 00:00:00 2001 From: Patrick Bogen Date: Mon, 2 Feb 2015 15:04:55 -0800 Subject: [PATCH 07/10] Add help entry for curl_get and update index --- Server/game/txt/help.indx | Bin 69648 -> 70464 bytes Server/game/txt/help.txt | 17 +++++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/Server/game/txt/help.indx b/Server/game/txt/help.indx index 93edeafbcfea7b3a318ec8ee61fbe7827918445e..87d0222d6485cc9955ec0fae94633b2373b8a742 100644 GIT binary patch literal 70464 zcmb8&31Aad`T+1zR77wUZ`Xr}f}(Z+@*7vBEG`&zHX^;S?(yzo8|yzu|MH%Y!XGw=I?S#)dp&6jW9yqS6P=FOYF z27WqInQr_q{ZIRCg}*;!GZxroYxK!nS63q2R>0plf12ALe^>Ty{FURUGY8_Yin;D| zvS1WAzj$}_b%A&^=8Z)0H_o4i?uEZAc~@PismT+p*Dkk4@lkJVN^8v96b^V|-l(DV z8}`Nc`v*Ktwe=o@^S8OsNBzNufH&3{@p|gvNBj%rrxAnkKWaU}23If?^Thn2prQBq zq3EZ2B7RS8!0Ylh`(xVd4P)^^=pm1QKi1+3c&B;;gpVAIKI*UcdVM}`9R#QR(Ie4& z0x_3AIMo}Bg(7|^P~B&24gMB<(9;Bv@y%n$Q+)j-D>jd;u;{LkH5wFi1@doR> z_8YMrXzFx>_1_t|oyoVWN{#Q># zpUh=)`GO(#VA3zGL%$%GO%)8@uWPhliT}kp7Voa+mz}5h^xRZ6zsnNE=Zd*%{`|k9PiN=CE}6^sGUfTg1?Y?U1QZbO zPrVTRyj(tORPl>1QhYjXs0 z^A(B@`rv5F`>+3wJ`idM#bXA$zVBX%K9kGMHmdm7uSQ?!N%c-;vMtbf>fJIsCo)Q{Vr?{}TDQdK0h>Xdijd z=6edMJk5U%J%ztC z;};Xfo`OO77oM^Cd@9ifCsfL>`me?(#BoKR&(1Gud?uHK{Xm=l7OyybcMhrp<$bT) zywtSc@=c9r^4a%oofj2Upa0r-Y(A6gfRg~}+uyVKSv_5F(Mp+Vf4O($WEvpWCzuQp%4C?R~)Z#JLHw7EoLaNVPefBYt! z?@FXI&}^dorN$PO1>j^IhCgsc>u-i%YU6LerQJv4KE^NTgT6b_kuqYuf25z)yIlqw z|IzKycje_buzu|h=uOVYKV=~Lj115FK|7;|Lz~z~*nIZd4ZXM=aaHll6fY0`RebxN z82<M-Gveo80=|rTBTB=|VRg$vMBujq%&y`n1E~{eEN7&+E(?)qLA{#Y5+FDlZbE zk8iOf&>s(7QPup*ia&ZY{LqOQf9PiT59-lRoM=?dXSPrAi2|HRq2zNb+fw4PR_hNw>zg_hggCAMlB!XpXt$V%G2m8Q*0tWaE0Tr*hHj3!3~>ZRsMB z|BAU9Ul1K-`t{v;fyU=k-HCMG(3R)OCuw{KEC9zvonO3A<6$?JB`Qys))Mlart!(1 zq9Gf^&h7iZGc>-KPj_^PCc4v4SfqML1bSRtjDKRW;@eViL!vvKNf~7Pht9Y7LNTA~ zg)0%#|Mf!Er{Q$L`=OVrUY?NH_;+5Wc+u7_z;`hDTz0wQ+j8cf$oSP)J3KUr>GdsM zt9sd?$@;a|DLyq9E?W%NxBW}?Vn5;iQMahRtE&HPx$3jfC7VscEf{k9ZgaQd+f(8T zSU>ZA)u-V~nfEguP<<|+O!2<`LDkDE05+e!A5nZqPZ|!ftUv!z#doIL;Jn59`H!nU zk%8^S`lFv#dZjl}y3il7Q@pQ;+BiKhXMcA`iDd zoZPtVL&A5M!A0{={dhmt`T%Tc8Qt#JeWLf`)`TV8&xq~iHe@f8(?9W}-OKGY9U8i^oRb@eZY2G*^aAGsU;eE1v3bM> zIPrI_kHdw48QiwPUfycU%I2P!5%p8%55AO(&2P7@*2lVYd9%9N{OkSnK9$M!=<4UD z{#qaHPC>t#vv`dDf71GTxOFeJEgfUx4t6hAx=>>fzI|uAm*pesr*`{Zx~tx&iaxjz z>|BBK_t1Kgzc&8Of7bd?cPgu0-(&aI`uap(zyA&%r1f>;O3#_SVZ82Aya2A*sosJ? z`W+8Yd`9?05t@fHd!U`Di+}ckq<0&zc%|}|e)#AhyBCd`o`h`PYJAV3w1-oZBff8h z-9sB9ofo4Z;CjvJH;uCUY%bp=`@^;Vj2gR77YxQfH`?x#i9Fo#hW>eN{Q9wW4;vQx zbvo1ChA#ih#@W4SqUU-C4RoTUzt>V_h$G`yLZD?I9)z-vZ{v*sUq)B zEh>IaPp+5{SNU}Ojq~l^RVYF~YXVA1cYGLiqQk>QNh+Te9R-@>XYy3^G96ciL&u== zczf6xq_5HWM;4)n6w&JTNA^~ur=8#?}0Yb-vO&5EWl?L+UY-W-epBd^H(`+i{Y?a;$&aQ=Z0Ek0dH zmQo`2-#b3BcroJJTm`}(`Kjum7Xk8-t4#Q_zp!{YLY(toe5HCBo{itt6q*sW%GG=gX+x@sa*Wf&lX=bf8TEwpH9H}h>QRH@2c;TE6n+|Tl5k8 zhx|-T$Pt%p{Qb95eYTL6ZF<-Ri2ATwU&X^%tpqFr?Gn--(_it4ZWz(Pd*7c_pEoNI z6aRo6RbQy;?-^+EJxS>8Eimy{?5z5tjL-RoT`fLmCPbIdn%yj3p53|f+;LCU_f%cq zfqPjzjF=F&X6bwm*hlsAV0-cYgh7fIb*Ei)55N(Ws6UN^6%WU@GN*k1A&O7UPZ!Gz z5b@tW(B@(67?;nqgB71lnB(f0{Qojs@x^p8lPWKyZ(prHOz|*QE-xP7k)1huzl~e< zVk9c>*Nj$t<#Z%Qx#;8f9ec*IN`=^dje0?YsF~sSM_8X2uFL-OfAB{2ox??mR zdd8^y+v;pS6!r$;AqL9-)ob&0fl$;-`?q~IABD#a<53v4t}oB_Mw_1&@yF!DjCz0F zB)xZ2@q>C_L-Cm7j&?+`W6gp}&*PBb@=qJht#(2L|i{ev>j5vXD@gF=+ z_2%J<^9LtXFPj@|{EOQZUpg9c@n?0a9)^~})hy@d%~pLbKMy(v#CVvm7OMGVlbIg4Wh{on6Xn19ET?z7pf{QD_bs;gcC$v%{-bj(zB`|4PtO;< z)kOTqmndE~KY2g?Z;B6?`xh5~uceANo2v%rPr6j~<_^R8nU`BU42+T|FLHgyT%+@F z5lobi=SJ0w-Y9s2O^h5P{DZeDzVtv5=Rdt&@wv(gl8oQ~PKz&}AW47jJr*ynzr+cW z^he&Wdh_~=^J`aFygVRs{-TFfZ*E`C|Mzj#n+Gh;k9u15=JgckFL*}vW(DQE|9OkA zTK>k1syDB9xcI)8R4=Ya`0aJotExAzN4WS0zp45{>H31M58bO(U%tMeec$&izI1&- z`%6Bw_|o+S?YH_w_2uge+JC>!;!D>Tv>*Pt>gSt}oCBx!_cdQyeCY^B`-{J^_+n*+ ziQ~!E-z#2J2hqLC+k)t8R`j9;`-@%hv&*}KH}uYXp(x&LzcJhDmkJy{r)AURc@ zUl?1Ne-HnjSV+w`s`#_|sJ?nWgSS?_Xer5Ca^&{?d|TBgdSO7M7(`F{?*0~!UqEc% zUAI@g9It35MEFgAQhiZA5i9N~QssHqPO49s3oyQA7uCZ9;pQW^Wc0 z`C^axR2&iifCE*Jhi7Vi&lsk7YejP4xQSe*}6l-;S@@VErCP zp)b#KSTa{eF>`e&+bRD{%ePKv;LL_d;A*K&u+B)(X2n% zZ}($Z|Ea@|W&Mql?D5C3zGJf8AI|!r0lOd1`i~S}+v1IcLQSmC1u=e|sBiuN^x4t% zb6rUBP@jXXp~(j0(^C{53I<_hg%|c2vi`puL0=E`)2QN)nyPphJrfDF$c(7{tGik8 z(9H$Ouzpz!dKk>(jR*~EOvV3dI{Jo?=-A`^fybk7^uSzSRs6?_pX_acryu$F=@}Rw z4p)=q$};&6ZABjs`rrU3W<;acx8(%%zCZ}3T7y+){AUUD!BFXl3x{*6JgvU9ya0K8 z`+lYxKOU_2MqstQWPGb{#RZ7t=R0j`d^k}=8x1bL)wkjTMEqN4O z`dFhmD<0?f?nDps?!gg)kN?*+`bqJou&6&=e9tWO;fQ}K%mm1KZ$|O)aM&B;^Z8iu z^59m*pPt3|Q~lAnC&0&lH-{ePyA$cK`LF6m-v|@%!SRIk3+AAY#$Z0Z7T%wpM<4SB zp!9ivaY6Mk6=Rk9GpdN*6RB(T$KVJJJ216BUe|*jjYF@bj!pxrg|>aT)hXzwdLy;s<`m~gEks`z3c~p@AWs2Q z{EHOt4>o$??vyygkolxf$M{X5plF}7{`WJ{dxBBFQN^!WguWS8w5cv68YpBwC!MYH zE_qi`cRy>;1*C^gW#@RyyDufZc6)t%73oLo;(z%st&g?@W1ePBKKtE-UX-UP;7;@bId>`V3wNP!Y6*q?b)x#y@h`p`Jyd7ddwIX`Ui6VrEzFh3 z`}y~y_rUeCXuNUxoW25m)Z>GzP2TVJ5PGN&!KhiN230@TJ%TO+H zcwJ0xHtqht7zjvD1U{@9x_c`gI z@zmruXW+pFj{6#Ytrx<%Ci?>cXoY%RTEFUB#fKW=QLH;!|G^Kc4+XrQplhlp5QpN? z`af?(Uutg{oPXyR)kkAdm%;i6e^oqOy^D#ux%fU~>q=oI^J1b4c(#?vKh?+KYdC*o zUxy#f`TG72KZf(!9njZDLgC@DP?YmG?ugzS^wf#=80RlkCaj0~GtK(Ql+TrWVtlxJ z3in=M7iawG``SJ1f{f1$MsH5T&ie}vKri}M;}I_#|BE4thi+bY){6B_!>rzHNz(QI zh7lU?Hpu|8MdU7N@o&XQ57TQmi0(Cuzcx<#h_}Jp3@uixpNc*P z0RzyG@yZ)`F0EfT&F;-JfTuz4FE|#x4{oQ3SC7C8ISk4VJi+N*v6e8TrOjtUQsd3u z4XwX%7UALOuPdK@^MtR_`$fHkAFcQ6PbK^qy}$TOjW3@gHQP6Ew#L^%H@!HgYW%rN zXb)W%j{39WBHGtzeBCnIkJk8pSJ8fq#=m<^fnMDI5?4qDlmBaXsvf#xgQ7`n z)*s#aetWOgN1=0o^UvO|_z?6Lf#!T<1^OnhQPscypyJ`=)&kMF_!A#RAC~uDU^ijb z_pB$-Lw{7QHzK})E}ui5L~lOc?MlKlTLpMZC8{gW^Pfc@^)`9Jjc|`PYLLF}zvv68 zu0(ey%xMdkcvSq^FQJ#6hhhUTe)+44k9nX4$@?qbKtIIzgMNrn>TeP4d6%~RV~G#b z8&n$)Z}B-p&KF7yotNi$i#JC`RnGmoA1of`PN?>=csWpxU&7)Yy;aU-Endu8TIFN$ z`6?Lx+Tx3U(9isXe)u2s@MLARk0t-MYTCBGbN--L-fcuJX~}0KrSSI_KMH?O{bccO zO5yJ<9=aZ?eJmdC=v4byyz(wKYB`G^ODX)l#gD_^Q$Jb!;grJPTl{$ZJ@u37qw!j} zv*>c>xuKSaNd>TfMxc~_lk)SoRr zss4@rXN!jicdC6X9$wl}?PKxn)wE$){E>gmi&xRWBeXr@i6S^{Pm1Bib_;e2%^}c**4z9oFVcDIM1rv%W!J zdRw6jXLNHL_UqYxKcW}o0is45>th?yn;l9~gNr}l7xYu%SQ=cWs3lN+R8vX#Sk^~@J3iCW~0|HL-v zORri1O#65Hp-n#XolpdU(6=Z1Ej}Z;lrhrucwSA4OP1fBll1fbr%0W+1uv%a1_cnJAPO zA@jNLX!K&LJF|S~{QVyEVy4q_I@J0GYtchK?U_V}OrP@Gd(p#d4pK$&4dMg;rz`&* z8qmZ0O7ddL&;sKZPDU?mDw~9-R?W50#kYGg1-@W{Bk1c$LRd%(?~y7=d+7dA8Lqrnwq>3 zs1x3(*1vZSdVf&d0EHz)B_;f-^He__dh7r*{(no*PdDp7>!189`amf>7ytf?&_nwc zGJ)Kge0IGUeK-`23d;Gpm!S7VBAynp02BZ6D->V;0>*EBC3?8t6f3~S@4QO!Q{Z*( z-c}fM9}#J3x9`9IsrPU>qV=`ct3K|JHbP{GPx%XPKp*tN2rrQd7ID5Pr1YkAH>mWAuK;D#DM|`zzij{5ZY;U>)HP*ZV`iA^do~ z@7O^2QPA0^Ii9cDM0x1!)A%j7=_^`C@?)tFqhJry_{M(dBVv3nR5)3G2)}AO^e{FP zMrQ`=V39&`Gkn17le=smUabiu~Ib$7)F!i}CLzi7gd`8>Rb-Fw7A zi1g3xiM~lv-cQ;~@iG@Vq|=<8slM$F6mQw~HA@#6t;1t9hVBL3eFLLY(q ziDHbkXueTCb1-^{50dvI4@K`Y7hvNL9D%+brn+;BuVC`oWb-vuyfG5v`}~op*de+2 zN4U{L`N$oZ^RvgQ-VD$A0prob@w3h&5@Oc3VS>d6ykc+vLmtLZfrslI?eW$bKjN7N zp1PjR9EJHb`Adb*c zQxf~j@_O`MSb=))*wLUj%h!7=o-F?xeU|uI?>}x<*KReV#uSWDI~ zoq=9He-waIhRBM@Kc7&1C=wqRnxd;=#E`vS@&v(nOVEijx7T@H7J7!$|2hTxY*JvIO zIe%wC_2Nuz9^R<(|D*@KCn}oGy#L2s^o3NaAaddIxw03%=)bLWZxi+H^Apjh#C0hI zm)+rn|Ls)t@O(;l1|FG|D?#{s&q5D#UqN@i?9Cr$5Pq8_=mW5|#KwYECjI`3hx4^K zT#4c#efI?ze;&Nev2uTb$Y=3V^x2*+brJ3HZOmopi@9P||MlhQq5hZarzj+C{Ijn_ z4_$S&@Bq13U($bfwbcV={jzJ(!?_5)L2x?$n19*5pN;>+jdpLY0W73l-`<-wUVH`N z``(6LynYH~Ai(%@??4|eFTnWc?nN)kM}7n2cYVO_1*Y>)K4kIYfiY+R{UHz7Alox< zJm!cG8^HVu-T7MY;VX#t>bR#J@%`l$(8bqzxwb_7$DVV|I&K&aK0-qLdJh|qvGSWL2u<0qc8uX ze?jkU7Hc35KBcp;rv9Jxo5N2FMZ|TdKK|`nY+I>OqHjZV&TxK*tl zUh#8&_-?ANd;xrietX@uC;Av%U5nP0`A6@!-dpvJa{F@rgnd;XlC_QV%U!CkEq5ot zBKmxe-5-6Re6d_Q0qc%Ge;%`X&EyA z=W5Xh;Q$R#q(u6s>(SSl_iI@Hq7S{v`S|-bqOUWz78~C^3BAer_$N(95A&n=!2W#pP!=m%_#pPqv)H>FJSXu6+_=ql+}Rs&rVf+s%m-u zrx|@l#II8RcTHD)_4s!jhdwo@di)tP&}YpB*!A7#1oX*-TmjZUl|V19$GuJP$e1iv zSanVN=Ra-eyHZ^UXbyTAzsw20TOPf5)sUFYQ$(lY?^0B~M_li- zesHhV!(DgQhflJ4n6E6}6g2x}b>-Q4hStN^=aH+#X?zBJhGKYs;Xg}uf=)pdtDGJZBK?AE&|`So_rKoZ zUEXM&M?BE3+rG!#r19kej+*1cNw+$^$V(1z)cF70?)3FyQc^J>QsaNU)9JkdPdF-O z9?OW3+d}i(l>ICtrDj_O8;% zOGBB@q2IGkFUnsGEriF%<;YakpZdJhR|d#x{Pb67?>3zAe|Zyq=}=f1fUENpSD_ad z)?#-r=cDuIyp0~7uZfyB%FF@2IzQuG^l-aF91GzO?bokC5A$bw#jRP+fA+r3mm0X@ z-lZ;|vp-b5ynvBOQGV{n=mX{j59=@d9DVa<_;0_mdZ_hm{J!6!56B6j%o3&Y-+ev$ zO!?sjScLMe8&sdmbrtydKmLLq>KjZq#rwfVKXI~^AJdBt5jvkcw?uCqH-R&LdSAQe zy|F%O9M{(#PWI>CpbTJrrNL8%_JC_fou=@T*Ebcerfc?Sk4v#~-ji zdSAdVhpTY@%mdIzyyA!`b^tnlzo8aiKID@7~3WJS$Oz37xt4ucYnXytJU=FQ1Jbj{fBX5Sh*~4C=Wn%K5w3hJ_JXT5+~!gE<)d|EI@7FzGtI{{>I7|Q2v~A(2JY(P?p0)%%JXk;eQ^lLlYq0*c z&lC^WFXl5CbbYS(2G7mxTJ+)J&+Z#y&m};eK6#Ywivum8rzA}zx+)0dc);0 z0aW~jebB@6EEP`q<=dba@x|1uqKqj2z;@^%euY#1g+HN>%K3$4bTa8^ z-wi!Xl!)Izl>bkAIK6Bz5&o(_JH45azP~ZEx7LfV(DqM`*%y7fJ(Ve>K$^q%wEnXF z(8K&2r71h)a5=62VX(!ES5$~EAoDq9h{Jco0;Ip=K=g&q4A4C5!^2cBa^d}uL(u1Q zMezk}{KTOaFTQ~F*9=FWOu!7C8SxeL`eqKZdcdsTeH8j=xNz5Ec!^O$smPa@e`(wM;=F2@mg#W~c9!8c1>fvoVvWN)(y&pZitOqFX zCpMvn7pzqE*G@qXeUoAVHlGWpqA%ve>y%5`6ZzLRqYsy#mlRck@V6d|K3HCW@vk0- zUd&fq$%crZn}NR4c4OlIH;G#v!EzTV#e?@NMjfIn3JV~ZAVV#dGKi#`N1=Ky8nx154rzP%}A-oc~tS#m1+X@1$( zkY7RhH_kvmy;R>sN|fJiF?zLnQvSKK(T6r8{yXQP4{V0NZ3%k$wgtJibpB^vfF2Le zv>&?^ebk)ZNn&b!+b>2Bw<}ABb2|PFm!bF9mwOv&|M3;*A^uclc#gJxGW$xa7x&Ud z^`!FO521&Ln_z+i zb9blW#~(%?4F~-4=?G?f?fMw{aQWcO_=g`?ym-B{NS^V#K8Zd69Vn%BCF|$2PouB( z#-@4YA(XDqFFu3br!GL8FAC42uZ0_alfANmLgsVUe-#h!Hy7($S_f@?8}=f4Uu|gt zrhKNngx>7_f#{6C{blq~5nhhyr^~19RfiY7Y2^C$f79jz{>kzHL6qm4Z`pjbv;g6+ zS&e?G*s*}v3~oH72jmuJmT_6f1>!hh&h9r*kHu^Zuk^^SX||Z+d+)q^qJ~QwV&~Od}HxY z*ZBCm{D5B8vnu{Q#ls7RAUGd?&5sx#y!qf1lmBNMEgs(QQ#zv(f{Dy zedDf*H#ZpTcitVnFA$O)%3MA#>|yg}pFWxYVSA&m^ZLaFwishU`uFxhUm9G*`kuk6 zH)jXn;*U50Jxm5tKL3*Wx2KOy5EGYow=G|d|sH4?(p<er4!FGf>&%&Tj%e0*cj%eUQCS>OMS zw|VmxGa3J&TBnC21nGD7IXxU9NPp>Mr-vg1={JPXCv(|iK9?!LDwF=_FnV~~5K!K) zj-hW)XNvN97AF3nX2s_+ZKVxN=5zV6=p*KIt)c>LrjN_+6Y;z}e2@0|_ti7h__F!W z#vh+R4^=@-aVEy9LwNo1_O&+jfk`4h@7*1$mtooXR$qO6Po9PG;qBU``#W_0KW5N3 z1VS)>NM#hC_WW{j7y1aKU(N55N8jw1w{pv)1hw&9Mf4^&Sl?$J`eyTSWY+J{i{9jX z{52<{7lVz(_?gluM{WKq7or#ajbaOP{@;tOzBLpOja*ntU*DR~vv{!ySbyCGR$ncC zY$@f4?ix`-4%hJVP?;d)ig#1JD5xsN7P~$3Nj3^vLP* z{P8;U0eH;8D{mIle&7x0{ZWsY(Nk<uy!O`3hXI!c_g-`Zm>z7xIaGXn(ol8)5v0e5I+mgm(WL zb-NlLy3@eQqZ?5^6Yfww^tj`YJZ=0p?o@qqc>!{L7u>D-C^XMY*%0|e?^S(0jPNzP zC#mvWe!uEVQ)w{eIpP7;mueg1?^}VsJoeD!`ua2ZF{?K_bL0}*@|^vg)kE8-{L%U+ zUb1@Sm1J7K?Q2%=f;sOZlcVB0w0_68(VN#(r2&_O|6cK>y|J}C%tiOS(#-cTe#KX& z)o?!lmHx=-OD`gZn(g%8f9mvJT)^@C+D>0PeR)s`e1XG%@SW3}kIl=T4u=nJ(E9Sc z><)kMZyImTnkCwB4u5r@0pl%6DU`p^4neQBVw(@z=T^e`o3=~B|^ zpB_kfw@aJ^9Qoh9o6}e33Dfvf_NKh(EOW*mJ=p1?-2qnb-#k#`OV3H@;u|BJUi31F z2D;AgU8C`Cz=U5tPUo>gi#LU+&traaq|U>cTfVy+zQpFg^=N%*V5ig1_mST0OSHv5 zFQD<5jU%7qrf58lBX;=7(==XLUHkg>9H;ZRx^}f`<2w`C4$3b-*%7}KULW6cs>7Rak0A27)9I5v`8>R~O&@>4X^!}S6J1pP{Z4my zF)4*X`SoWxJWLx3kL3{g4_oZ;=4+@3zf$pCiFC%uyIB9*c^F@KS1|{#4J(lOhnJv- z+1LX!4&UWa_zvd#FPh`?CtgT=W{`pJv9`;^s{q$UJ^SNRt z>@(tZlv=;S?h|cY=`8Ix+I?z%qN_UtE1-|xbA>IRd}?kwHIFQx)mPfQ+`5A6v{5b5aSM{cnBo~+17v~jfMf7*?9FXGewuA6Lr zChx!fx7|a9VB(Ls#p;KPqZLy=hum)S^YZB;<5Tz8ym?TE>Z3281ManY7wlwNBTxFf z9^|L*O%!|J1TT)d4&U&;&CgBc3u1Cq!vDkW^Ql>>WKo0&N# z=<*r=k;0Qs+I$wKh&O2e z;8r%jAkhtPek9}X+Sld_scakL8wY5-Yo?e9rB|+%?fUE29dzD2XzBdgT{PZp$b+2D zKe?yIyRcDXFaIg~*u0n%zt^ZVg6#g${cIlU=Db9{%_udR>^?cf=4I=F_UjL_dGU@? zgZ70(Y`##0qaoBDBA;0!wcbtnjbm)S+&U-XFCA<1`4pT>Gh{xGOwf8VpWlzt`Wh<# zGbY-6S0X>#$dKNsxA~r|T!M;!rO)Q!B?B;tAi2K%{WdROa0@k=D9=fgY`z_`<2M?UEpdSB?7DbMrv{GUBR@6E$R(XjjPlX_o1OxXRb z4!xHxGS~`s-bQWIT49yg~KWnz$7rHZP;10j0OYdj(6y(;m$KPWP;d9WehtjwE z(+heJhZRHT_nWKt?V=R~(e3enny>fCq@nfwPt^OFuz)W9C#UFrg79CTs`oN~d0@2e zFH6qQd$GEb+xD+R7SY}i$6cGh=4`DWZiwR4`2Eh)dU?VY`=q=QQ|9Y?;V)XBXp_?E zkG(+aOS_AR4wvRi{M|0n`tntn!@s+X^KOW4jepOTHZR)qM!CSr)%@dN{54zdr+vEZU z%ws{*t={+c!z&tt;4$wIVi)>`T-xI zhgn_yfqR0 z@Aw^hF`q`OCmsvIfQiZ%h)So#f989=hasKiMJztP9(_~1S>1!RKK~r%!1 z=as}Ye$U^~`|FIVevI)aSRwNR?*gs$#0)n6fGyFB(t$bY#QiU`9%%BJvW?ZlGo>-{ zyntL$jla7u`gqg}ufTxmUKqbufAr$vO?cx64A+gyW~%rO_+!~#{vEa6P37~_F6hOM z0>g{UNfAU~P5hU3M=!e$tN1MEsxk zMGq6<;QMw7f2|8WCPT-+aewsU`PPVBUoo0QU!KbkK<|UGvEGPSO5AzZ``#gT4|5zt zosf%Yw%3J2(ZjeLcqAceaQ@9<4(~RY_`wl&?AC zAiNl8r^#o=k%S+k_y2b^;m7LzVh`cR>HR;wgg;#GZ}2&MUBDBKibI5Meb1dldDsA& z^0_JC@TFPd&0`QOVmbc&97LZ_b@XHsdARt3PWpnli{xtW$tH{NLjjhOpIw^K!;RKr zXIHA2PAbmkpFbXbTcVhN+b=0sIt$mo@McrZH=Ny$9=aM+d2y@K1y7Qc?rSOEB=fms z7W$4v7Ztm*1}ih@MIV$BPhH!JUtXlV+fbIR_|65CuhIG|7gBz-)<1We;&UD5Ca`P( zxwR_!e0_$+%hJS+Dwx$Dx(Iz&x{yp|GKp*o?x!d#3ky}^4?homPIfU8Tenn$p1pAM zyg0mw&&|uw!^?boQ+Xo3$&C?Lq0gr>vW`Io!d14_&l|2$J=`oS_PR2uxhZuKwf_I( zTJ-R~VCcY6VwZLm)i1u8_HM)6wN$^y-L$XK_$wYnpU4){N;U+bL_w(o%?7jJ{PV; zpUgm~EmR0x1+!YJ{^Hlrn>XFtSl|B*^l+vQw3>sBOSw4XfA%JNac5H;HKD4L{x56L zj~X#@#K`WE&?`XuAKzE~n5sVV0ebgl#DDA~^fjB|lb@&_zM)F~pRcp}(N+AdpW6K> zwtUY0%PNxxfr}r!#_suiR$gcKd_G6rW%ceV`PANL_k2D}AF}$ID)BFU%u3tL&c7|Isye&*y*Mr*_Zh|KZnmFLrl&eHVUj_hNUa N{qzl1Kc-6g{6D`}L6QIf literal 69648 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 O_UrGo`{6aV&;J8`{iIO< diff --git a/Server/game/txt/help.txt b/Server/game/txt/help.txt index 11671e86b..2786987a1 100644 --- a/Server/game/txt/help.txt +++ b/Server/game/txt/help.txt @@ -25374,6 +25374,23 @@ Mail: Done lparent() - Returns all the parents of an object. die() - Rolls a set of dice for random number generation. +& CURL_GET() + Function: curl_get() + + This is a minimal implementation of libcURL bindings for RhostMUSH. This + function allows you to retrieve the result of an HTTP GET from the given URL. + + The implementation is currently quite bare. In particular, you cannot set + headers or cookies, nor can you access response headers. Expect this + implementation to improve with time. + + Example: + + th >> [curl_get(example.com)] + >> + + ... + & revisions All credits to players, codebases, or other is presented in the RHOST.CHANGES file in the readme directory in the source distribution. The credits are too From 8db952811ab7641ceb8e15358462bbe533c84387 Mon Sep 17 00:00:00 2001 From: Patrick Bogen Date: Mon, 2 Feb 2015 15:08:28 -0800 Subject: [PATCH 08/10] Add wizhelp entry for curl_request_limit and update index --- Server/game/txt/wizhelp.indx | Bin 43344 -> 44400 bytes Server/game/txt/wizhelp.txt | 18 ++++++++++++------ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/Server/game/txt/wizhelp.indx b/Server/game/txt/wizhelp.indx index f5171b2a057f5329d4ef4ac5eab189cd82fea359..69d49087d22cca72d271645fdd0584554e518a79 100644 GIT binary patch delta 9459 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. Default: 5 + + This specifies the maximum number of seconds for which a cURL request may + run before it's cancelled. + & dark_sleepers Config directive: dark_sleepers . Default: yes Indicates whether or not disconnected players are to be considered 'dark', From 965bd985cb98385197c0b7b2423874d352e30a5c Mon Sep 17 00:00:00 2001 From: Patrick Bogen Date: Mon, 2 Feb 2015 15:25:06 -0800 Subject: [PATCH 09/10] Normalize line endings in responses so that operations on %r work as expected. --- Server/src/curl.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/Server/src/curl.c b/Server/src/curl.c index cdf51d929..739f8102e 100644 --- a/Server/src/curl.c +++ b/Server/src/curl.c @@ -28,6 +28,7 @@ FUNCTION(local_fun_curl_get); static size_t write_callback( void * contents, size_t size, size_t nmemb, void *userp ); +void curl_normalize_line_endings( char * buf, size_t buffer_length ); char tempbuff[LBUF_SIZE]; char tempbuff2[LBUF_SIZE]; @@ -116,9 +117,11 @@ FUNCTION(local_fun_curl_get) overflow = 0; result = curl_easy_perform( curl ); if( result == CURLE_OK ) { + curl_normalize_line_endings( tempbuff2, LBUF_SIZE ); safe_str( tempbuff2, buff, bufcx ); } else { if( overflow == 1 ) { + curl_normalize_line_endings( tempbuff2, LBUF_SIZE ); strncpy( tempbuff, tempbuff2, LBUF_SIZE ); } else { snprintf( tempbuff, LBUF_SIZE, "#-2 GET FAILED: %s", curl_easy_strerror( result ) ); @@ -129,6 +132,24 @@ FUNCTION(local_fun_curl_get) curl_easy_cleanup( curl ); } +void curl_normalize_line_endings( char * buf, size_t buffer_length ) { + size_t pos = 0, dpos=0; + char normalized[LBUF_SIZE]; + size_t len = strlen( buf ); + for( pos = 0; pos < (len < LBUF_SIZE-1 ? len : LBUF_SIZE-1); pos++ ) { + // Basically, discard all \r, replace with \n with \r\n. + if( buf[pos] == '\r' ) + continue; + if( buf[pos] == '\n' ) { + normalized[dpos++] = '\r'; + } + normalized[dpos++] = buf[pos]; + normalized[dpos] = '\0'; + } + strncpy( buf, normalized, LBUF_SIZE ); + return; +} + static size_t write_callback( void * contents, size_t size, size_t nmemb, void *userp ) { size_t realsize = size * nmemb; size_t bytesleft = LBUF_SIZE - strnlen( tempbuff2, LBUF_SIZE ) - 1; From 176bb85327c8ef4f41b57cfedb51c7efcaaf4538 Mon Sep 17 00:00:00 2001 From: Patrick Bogen Date: Mon, 2 Feb 2015 16:59:07 -0800 Subject: [PATCH 10/10] first few curl_get options, parsing framework, whitespace normalization --- Server/src/curl.c | 108 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 91 insertions(+), 17 deletions(-) diff --git a/Server/src/curl.c b/Server/src/curl.c index 739f8102e..1e5661ec0 100644 --- a/Server/src/curl.c +++ b/Server/src/curl.c @@ -26,21 +26,31 @@ #include "vattr.h" -FUNCTION(local_fun_curl_get); -static size_t write_callback( void * contents, size_t size, size_t nmemb, void *userp ); -void curl_normalize_line_endings( char * buf, size_t buffer_length ); - char tempbuff[LBUF_SIZE]; char tempbuff2[LBUF_SIZE]; regex_t curl_has_protocol, curl_valid_url; uint8_t overflow = 0; +struct curl_options { + uint8_t response_code; + uint8_t response_headers; +}; + +FUNCTION(local_fun_curl_get); +static size_t write_callback( void * contents, size_t size, size_t nmemb, void *userp ); +void curl_normalize_line_endings( char * buf, size_t buffer_length ); +void curl_prepend_metadata( char * buf, struct curl_options * opts, CURL * curl ); + static int ival(char *buff, char **bufcx, int result) { sprintf(tempbuff, "%d", result); safe_str(tempbuff, buff, bufcx); return 0; } +void initialize_curl_options( struct curl_options * opts ) { + memset( opts, 0, sizeof( struct curl_options ) ); +} + void local_curl_init() { FUN *fp; char *buff, *cp, *dp; @@ -53,7 +63,7 @@ void local_curl_init() { {NULL, NULL, 0, 0, 0, 0} }; -/* Register the functions */ + /* Register the functions */ buff = alloc_sbuf("init_curl_functab"); for (fp = fun_table ; fp->name ; fp++) { cp = (char *) fp->name; @@ -68,18 +78,54 @@ void local_curl_init() { } } +uint8_t parse_curl_options( char ** fargs, size_t nfargs, struct curl_options * opts, char * buff, char ** bufcx ) { + char * expressionlist_saveptr = NULL; + char * expression_saveptr = NULL; + char * expression = NULL; + char * key = NULL; + char * value = NULL; + size_t i; + for( i = 1; i < nfargs; i++ ) { + expression = strtok_r( fargs[i], " ", &expressionlist_saveptr ); + while( expression != NULL ) { + key = strtok_r( expression, "=", &expression_saveptr ); + if( key != NULL ) { + if( strcasecmp( key, "response_code" ) == 0 ) { + opts->response_code = 1; + } else if( strcasecmp( key, "response_headers" ) == 0 ) { + opts->response_headers = 1; + } else { + safe_str( "#-1 UNHANDLED OPTION ", buff, bufcx ); + safe_str( expression, buff, bufcx ); + return 1; + } + value = strtok_r( NULL, "=", &expression_saveptr ); + } + expression = strtok_r( NULL, " ", &expressionlist_saveptr ); + } + } + return 0; +} + FUNCTION(local_fun_curl_get) { CURL * curl = NULL; CURLcode result; + struct curl_options opts; + + initialize_curl_options( &opts ); if( nfargs < 1 ) { - safe_str( "#-1 CURL_GET EXPECTS 1 ARGUMENT [RECEIVED ", buff, bufcx ); + safe_str( "#-1 CURL_GET EXPECTS 1 OR MORE ARGUMENTS [RECEIVED ", buff, bufcx ); ival( buff, bufcx, nfargs ); safe_str( "]", buff, bufcx ); return; } + if( nfargs >= 2 ) + if( parse_curl_options( fargs, nfargs, &opts, buff, bufcx ) != 0 ) + return; + if( curl == NULL ) curl = curl_easy_init(); if( !curl ) { @@ -110,19 +156,25 @@ FUNCTION(local_fun_curl_get) curl_easy_setopt( curl, CURLOPT_FOLLOWLOCATION, 1L ); curl_easy_setopt( curl, CURLOPT_WRITEFUNCTION, write_callback ); + curl_easy_setopt( curl, CURLOPT_WRITEDATA, &opts ); curl_easy_setopt( curl, CURLOPT_TIMEOUT, mudconf.curl_request_limit ); + if( opts.response_headers ) { + curl_easy_setopt( curl, CURLOPT_HEADER, 1 ); + } // truncate tempbuff2; this will hold our returned data tempbuff2[0] = '\0'; overflow = 0; result = curl_easy_perform( curl ); if( result == CURLE_OK ) { + curl_prepend_metadata( tempbuff2, &opts, curl ); curl_normalize_line_endings( tempbuff2, LBUF_SIZE ); safe_str( tempbuff2, buff, bufcx ); } else { if( overflow == 1 ) { - curl_normalize_line_endings( tempbuff2, LBUF_SIZE ); strncpy( tempbuff, tempbuff2, LBUF_SIZE ); + curl_prepend_metadata( tempbuff, &opts, curl ); + curl_normalize_line_endings( tempbuff, LBUF_SIZE ); } else { snprintf( tempbuff, LBUF_SIZE, "#-2 GET FAILED: %s", curl_easy_strerror( result ) ); } @@ -132,6 +184,20 @@ FUNCTION(local_fun_curl_get) curl_easy_cleanup( curl ); } +void curl_prepend_metadata( char * buf, struct curl_options * opts, CURL * curl ) { + long resp_code; + char metabuff[LBUF_SIZE]; + char result[LBUF_SIZE]; + result[0] = '\0'; + if( opts->response_code ) { + curl_easy_getinfo( curl, CURLINFO_RESPONSE_CODE, &resp_code ); + snprintf( metabuff, LBUF_SIZE, "%ld\n", resp_code ); + strncat( result, metabuff, LBUF_SIZE ); + } + strncat( result, buf, LBUF_SIZE ); + strncpy( buf, result, LBUF_SIZE ); +} + void curl_normalize_line_endings( char * buf, size_t buffer_length ) { size_t pos = 0, dpos=0; char normalized[LBUF_SIZE]; @@ -143,6 +209,11 @@ void curl_normalize_line_endings( char * buf, size_t buffer_length ) { if( buf[pos] == '\n' ) { normalized[dpos++] = '\r'; } + // Avoid chance of buffer overflow + if( dpos == LBUF_SIZE-1 ) { + normalized[dpos] = '\0'; + break; + } normalized[dpos++] = buf[pos]; normalized[dpos] = '\0'; } @@ -151,16 +222,19 @@ void curl_normalize_line_endings( char * buf, size_t buffer_length ) { } static size_t write_callback( void * contents, size_t size, size_t nmemb, void *userp ) { - size_t realsize = size * nmemb; - size_t bytesleft = LBUF_SIZE - strnlen( tempbuff2, LBUF_SIZE ) - 1; - if( realsize < bytesleft ) { - strncat( tempbuff2, contents, realsize ); - return realsize; - } else { - strncat( tempbuff2, contents, bytesleft ); - overflow = 1; - return bytesleft; - } + struct curl_options * opt = userp; + size_t realsize; + size_t bytesleft; + realsize = size * nmemb; + bytesleft = LBUF_SIZE - strnlen( tempbuff2, LBUF_SIZE ) - 1; + if( realsize < bytesleft ) { + strncat( tempbuff2, contents, realsize ); + return realsize; + } else { + strncat( tempbuff2, contents, bytesleft ); + overflow = 1; + return bytesleft; + } } #endif