Merge branch 'maint'

* Bug726449 - Budget Barchart does not show up if running sum is selected
* Add fixed EUR-LVL conversion rate to gnc_euro_rates
* Update Latvian translation
* Add Indian Konkani translation
* Remove unused function yahoo-get-historical-quotes
* Fix handling of kvps for address, entry, job, order and taxtable objects
* Prevent older gnucash versions from loading data files with said kvps
This commit is contained in:
Geert Janssens 2014-04-24 12:14:59 +02:00
commit e6c36983d4
33 changed files with 52561 additions and 8031 deletions

View File

@ -83,7 +83,7 @@ AC_DEFINE_UNQUOTED(GNUCASH_LATEST_STABLE_SERIES, "$GNUCASH_LATEST_STABLE_SERIES"
[Most recent stable GnuCash series])
dnl Set of available languages.
ALL_LINGUAS="ar bg ca cs da de el en_GB es_NI es eu fa fi fr he hu it ja ko lt lv nb ne nl pl pt_BR pt ro ru rw sk sv ta tr uk vi zh_CN zh_TW"
ALL_LINGUAS="ar bg ca cs da de el en_GB es_NI es eu fa fi fr he hu it ja ko kok kok@latin lt lv nb ne nl pl pt_BR pt ro ru rw sk sv ta tr uk vi zh_CN zh_TW"
GETTEXT_PACKAGE=gnucash
AC_SUBST(GETTEXT_PACKAGE)
@ -436,7 +436,6 @@ AC_CHECK_FUNCS(gethostid link)
# - check minimum version
# - determine GUILE_CFLAGS and GUILE_LIBS
# - test if guile module (www main) is present on the system
# Note: systems that install both guile 1.8 and guile 2 use different
# names for the 1.8 and 2.0 autoconf macros to avoid conflicts.
# So the tests below will check for known macro names in the order
@ -447,17 +446,14 @@ gnc_have_guile_www=no
PKG_CHECK_MODULES(GUILE,
[guile-1.8 >= 1.8.5],
[m4_ifdef([GUILE1_8_PROGS],
[ GUILE1_8_PROGS
GUILE1_8_MODULE_AVAILABLE(gnc_have_guile_www,[(www main)]) ],
[ GUILE_PROGS
GUILE_MODULE_AVAILABLE(gnc_have_guile_www,[(www main)]) ])
[ GUILE1_8_PROGS ],
[ GUILE_PROGS ])
], [
PKG_CHECK_MODULES(GUILE,
[guile-2.0 >= 2.0.0],
[m4_ifdef([GUILE_PROGS],
[ GUILE_PROGS
gnc_have_guile_2=yes
GUILE_MODULE_AVAILABLE(gnc_have_guile_www,[(www main)]) ],
gnc_have_guile_2=yes ],
[ AC_MSG_ERROR([ guile 2 is found on your system, but appears
to export different autoconf macros than what we expected. Please report this as a bug
in GnuCash, so we can fix this for your platform.]) ])
@ -470,7 +466,6 @@ PKG_CHECK_MODULES(GUILE,
])
AM_CONDITIONAL(GNC_HAVE_GUILE_2, test "${gnc_have_guile_2}" = yes)
AM_CONDITIONAL(GNC_HAVE_GUILE_WWW, test "${gnc_have_guile_www}" = yes)
### --------------------------------------------------------------------------
@ -1378,7 +1373,6 @@ AC_CONFIG_FILES(
doc/examples/Makefile
intl-scm/Makefile
lib/Makefile
lib/guile-www/Makefile
lib/libc/Makefile
lib/stf/Makefile
packaging/Makefile

View File

@ -1,7 +1,7 @@
if GNUCASH_ENABLE_GUI
SUBDIRS = libc guile-www stf
SUBDIRS = libc stf
else
SUBDIRS = libc guile-www
SUBDIRS = libc
endif
EXTRA_DIST = README

View File

@ -1,121 +0,0 @@
2002-01-09 Rob Browning <rlb@defaultvalue.org>
* Makefile.am: handle conditional install inclusion of GUILE_WWW.
2001-12-08 Dave Peticolas <dave@krondo.com>
* Makefile.am (Repository): clean .scm-links
2001-11-28 Rob Browning <rlb@defaultvalue.org>
* .cvsignore: add .scm-links
* lib/guile-www/Makefile.am
(.scm-links): create so we can run from gnucash build dir.
2001-02-04 Marius Vollmer <mvo@zagadka.ping.de>
* http.scm: Use (ice-9 rdelim) if `read-line' not defined. Thanks
to Thien-Thi Nguyen.
2000-06-04 Mikael Djurfeldt <mdj@mdj.nada.kth.se>
* main.scm (www:get): Pass url as single arg.
(Thanks to Dale P. Smith.)
1998-07-27 Jim Blandy <jimb@red-bean.com>
* Test of EGCS repository access.
1997-12-24 Tim Pierce <twp@skepsis.com>
* cgi.scm (init-environment): Make server-software and
server-protocol optional.
1997-12-22 Tim Pierce <twp@skepsis.com>
* cgi.scm (read-raw-form-data): Add `cgi-' to content-length.
(parse-form): Change `url-decode' to `url:decode'.
Mon Oct 20 18:06:10 1997 Jim Blandy <jimb@totoro.red-bean.com>
* configure.in: Update version to 1.0b.
configure: Regenerated.
* Makefile.in, aclocal.m4, configure: Regenerated w/automake 1.2c.
* url.scm (url:scheme, url:host, url:port, url:path): Move
accessors up.
(url:address): New accessor for "mailto:" URLs.
(url:unknown): New accessor for unrecognized URL types.
(url:user): New accessor for "ftp" URLs.
(url:make, url:make-http, url:make-ftp, url:make-mailto): New
constructors for URL objects.
(url-regexp): Replaced by...
(http-regexp, ftp-regexp, mailto-regexp): Separate regular
expressions for different URL schemes.
(url:parse): Use the above to handle ftp and mailto URLs, and also
do something graceful with unrecognized garbage.
(url:unparse): New function, for turning a parsed url into a
string.
* http.scm (add-open-connection!, get-open-connection): Incomplete
code replaced with dummy definitions, so we can give it to Mikael
immediately.
(http:request): Close the socket after we're done reading the
body.
* http.scm (http:request): Reformatted for readability.
* http.scm (http:request): Don't expect a body in reply to a
"HEAD" request, even though we do get a "content-length" header.
Tue Jun 17 17:27:04 1997 Tim Pierce <twpierce@bio-5.bsd.uchicago.edu>
* http.scm: (http:request): Force "/" onto the beginning of the
"path" variable unconditionally. We must do this because of a
stupid incompatibility between the URL RFC and HTTP RFC.
* http.scm: (parse-status-line): New function.
(http:request): Use parse-status-line instead of
separate-fields-discarding-char (which does not work when a status
line contains more than two spaces).
(separate-fields-discarding-char): Removed.
Tue Jun 17 01:45:59 1997 Tim Pierce <twp@twp.tezcat.com>
* http.scm (http:request): Change calling conventions to accept a
method and a URL rather than a port and request string. Do some
sanity checking on arguments.
(http:get): Pass a single URL argument to http:request.
(http:open): Permit port argument to be #f in addition to '().
(display-with-crlf): Make port argument optional.
(add-open-connection!): Braino fix (set! for setq).
* Makefile: New file. (Oops.)
Mon Jun 16 17:49:20 1997 Tim Pierce <twpierce@bio-5.bsd.uchicago.edu>
Release preparations.
* Makefile.am, configure.in, install-sh, mkinstalldirs, missing:
New files.
* Makefile.in, configure, aclocal.m4: Generated, not re.
* README: New file.
Sun Jun 15 00:50:22 1997 Tim Pierce <twp@twp.tezcat.com>
* http.scm: add some support for persistent connections.
(http:connect): check get-open-connection before creating a new
socket, and call add-open-connection! after creating one.
(add-open-connection!): New function.
(get-open-connection): New function.
Mon Jun 9 23:42:32 1997 Tim Pierce <twp@twp.tezcat.com>
New WWW module.
* cgi.scm: New file.
* http.scm: New file.
* main.scm: New file.
* url.scm: New file.
* wwwcat: New file.

View File

@ -1,39 +0,0 @@
if GNC_HAVE_GUILE_WWW
# Do nothing.
else # !GNC_HAVE_GUILE_WWW
gncscmdir = ${GNC_SHAREDIR}/guile-modules/www
gncscm_DATA = cgi.scm http.scm main.scm url.scm
noinst_DATA = .scm-links
if GNUCASH_SEPARATE_BUILDDIR
SCM_FILE_LINKS = ${gncscm_DATA}
endif
.scm-links:
$(RM) -rf www
mkdir -p www
if GNUCASH_SEPARATE_BUILDDIR
for X in ${SCM_FILE_LINKS} ; do \
$(LN_S) -f ${srcdir}/$$X . ; \
done
endif
( cd www; for A in $(gncscm_DATA) ; do $(LN_S) -f ../$$A . ; done )
if ! OS_WIN32
# Windows knows no "ln -s" but uses "cp": must copy every time (see bug #566567).
touch .scm-links
endif
clean-local:
$(RM) -rf www
CLEANFILES = .scm-links
DISTCLEANFILES = ${SCM_FILE_LINKS}
endif # GNC_HAVE_GUILE_WWW (else clause)
EXTRA_DIST = README README.gnucash wwwcat cgi.scm http.scm main.scm url.scm

View File

@ -1,66 +0,0 @@
This is an alpha release of the Guile WWW library, version 1.0.
Roadmap:
The (www http) library includes some support for navigating HTTP
connections. http:open, http:request and http:get may be used for
opening connections and making HTTP requests; http:make-message,
http:message-body and http:message-header may be used to
manipulate HTTP messages. Support is planned for the full
HTTP/1.1 protocol, including cookies and persistent connections.
(www url) provides url:parse for parsing a URL into its component
parts, and the selector functions url:scheme, url:host, url:port
and url:path for selecting individual components of a parsed URL.
For individual components that may have been URL-encoded in
transit, url:decode translates a string into its raw (unencoded)
form.
(www cgi) provides some functions helpful in writing CGI scripts
painlessly. The focus is on scripts to process interactive forms.
cgi:init reads any form data and initializes a CGI environment.
cgi:form-data? determines whether any form data has been returned
by a browser for processing. cgi-value returns the value
associated with a form variable, and cgi-names and cgi-values
return all of the names and values present in the current form.
(www main) provides www:get, which decodes a URL and invokes the
appropriate protocol handler for retrieving the desired object.
It is intended to be a generic interface useful for retriving data
named by any URL.
wwwcat is an example script of how www:get and other functions
might be used by a Guile application.
A generic guide to hacking on Guile software follows.
Tim Pierce
twp@tezcat.com
Hacking It Yourself ==================================================
As distributed, the Guile WWW library needs only a Unix system to build
and install. However, its makefiles, configuration scripts, and a few
other files are automatically generated, not written by hand. If you
want to make changes to the system (which we encourage!) you will find
it helpful to have the tools we use to develop it. They are the
following:
Autoconf 2.12 --- a system for automatically generating `configure'
scripts from templates which list the non-portable features a
program would like to use. Available in
"ftp://prep.ai.mit.edu/pub/gnu".
Automake 1.1p --- a system for automatically generating Makefiles that
conform to the (rather Byzantine) GNU coding standards. The
nice thing is that it takes care of hairy targets like 'make
dist' and 'make distclean', and automatically generates
Makefile dependencies. Available in
"ftp://ftp.cygnus.com/pub/tromey".
libtool 0.9d --- a system for managing the zillion hairy options needed
on various systems to produce shared libraries. Available in
"ftp://alpha.gnu.ai.mit.edu/gnu".
You are lost in a little maze of automatically generated files, all
different.

View File

@ -1,8 +0,0 @@
This is a stripped down version of the guile-www CVS module. All of
the automakery has been removed and it's been reconfigured to work
with gnucash. In the long run, we'll probably switch to use whatever
becomes the guile standard for www access.
This code is only used if we don't detect that you have a functional
(www main) module via (use-modules (www main)) during configure.

View File

@ -1,185 +0,0 @@
;;;; cgi.scm: Common Gateway Interface support for WWW scripts.
(define-module (www cgi)
:use-module (www url))
;;;; Copyright (C) 1997 Free Software Foundation, Inc.
;;;;
;;;; This program 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 2, or (at your option)
;;;; any later version.
;;;;
;;;; This program 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 this software; see the file COPYING. If not, write to
;;;; the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
;;;; Boston, MA 02111-1307 USA
;;;;
(define form-variables '())
;;; CGI environment variables.
;;; Should these all be public?
(define-public cgi-server-software-type #f)
(define-public cgi-server-software-version #f)
(define-public cgi-server-hostname #f)
(define-public cgi-gateway-interface #f)
(define-public cgi-server-protocol-name #f)
(define-public cgi-server-protocol-version #f)
(define-public cgi-server-port #f)
(define-public cgi-request-method #f)
(define-public cgi-path-info #f)
(define-public cgi-path-translated #f)
(define-public cgi-script-name #f)
(define-public cgi-query-string #f)
(define-public cgi-remote-host #f)
(define-public cgi-remote-addr #f)
(define-public cgi-authentication-type #f)
(define-public cgi-remote-user #f)
(define-public cgi-remote-ident #f)
(define-public cgi-content-type #f)
(define-public cgi-content-length #f)
(define-public cgi-http-accept-types #f)
(define-public cgi-http-user-agent #f)
;;; CGI high-level interface
;;;
;;; A typical CGI program will first call (cgi:init) to initialize
;;; the environment and read in any data returned from a form. Form
;;; data can be extracted conveniently with these functions:
;;;
;;; (cgi:values NAME)
;;; Fetch any values associated with NAME found in the form data.
;;; Returned value is a list, even if it contains only one element.
;;; (cgi:value NAME)
;;; Fetch only the CAR from (cgi:values NAME). Convenient for when
;;; you are certain that NAME is associated with only one value.
(define-public (cgi:init)
(init-environment)
(and cgi-content-length
(parse-form (read-raw-form-data)))
(and cgi-query-string
(parse-form cgi-query-string)))
(define-public (cgi:values name)
(assoc-ref form-variables name))
(define-public (cgi:value name)
;; syntactic sugar for obtaining just one value from a particular key
(let ((values (cgi:values name)))
(and values (car values))))
(define-public (cgi:names) (map car form-variables))
(define-public (cgi:form-data?) (not (null? form-variables)))
;;;; Internal functions.
;;;;
;;;; (parse-form DATA): parse DATA as raw form response data, adding
;;;; values as necessary to `form-variables'.
;;;; (read-raw-form-data): read in `content-length' bytes from stdin
;;;; (init-environment): initialize CGI environment from Unix env vars.
(define (parse-form raw-data)
;; get-name and get-value are used to parse individual `name=value' pairs.
;; Values are URL-encoded, so url:decode must be called on each one.
(define (get-name pair)
(let ((p (string-index pair #\=)))
(and p (substring pair 0 p))))
(define (get-value pair)
(let ((p (string-index pair #\=)))
(and p (url:decode (substring pair (+ p 1))))))
(for-each (lambda (pair)
(let* ((name (get-name pair))
(value (get-value pair))
(old-value (cgi:values name)))
(set! form-variables
(assoc-set! form-variables
name
(cons value (or old-value '()))))))
(separate-fields-discarding-char #\& raw-data)))
(define (read-raw-form-data)
(and cgi-content-length (read-n-chars cgi-content-length)))
(define (init-environment)
;; SERVER_SOFTWARE format: name/version
(let ((server-software (getenv "SERVER_SOFTWARE")))
(if server-software
(let ((slash (string-index server-software #\/)))
(set! cgi-server-software-type (substring server-software 0 slash))
(set! cgi-server-software-version (substring server-software (1+ slash))))))
(set! cgi-server-hostname (getenv "SERVER_NAME"))
(set! cgi-gateway-interface (getenv "GATEWAY_INTERFACE"));"CGI/revision"
(let* ((server-protocol (getenv "SERVER_PROTOCOL")))
(if server-protocol
(let ((slash (string-index server-protocol #\/)))
(set! cgi-server-protocol-name (substring server-protocol 0 slash))
(set! cgi-server-protocol-version (substring server-protocol (1+ slash))))))
(let ((port (getenv "SERVER_PORT")))
(set! cgi-server-port (and port (string->number port))))
(set! cgi-request-method (getenv "REQUEST_METHOD"))
(set! cgi-path-info (getenv "PATH_INFO"))
(set! cgi-path-translated (getenv "PATH_TRANSLATED"))
(set! cgi-script-name (getenv "SCRIPT_NAME"))
(set! cgi-remote-host (getenv "REMOTE_HOST"))
(set! cgi-remote-addr (getenv "REMOTE_ADDR"))
(set! cgi-authentication-type (getenv "AUTH_TYPE"))
(set! cgi-remote-user (getenv "REMOTE_USER"))
(set! cgi-remote-ident (getenv "REMOTE_IDENT"))
(set! cgi-content-type (getenv "CONTENT_TYPE"))
(set! cgi-query-string (getenv "QUERY_STRING"))
(and cgi-query-string
(string-null? cgi-query-string)
(set! cgi-query-string #f))
(let ((contlen (getenv "CONTENT_LENGTH")))
(set! cgi-content-length (and contlen (string->number contlen))))
;; HTTP_ACCEPT is a list of MIME types separated by commas.
(let ((types (getenv "HTTP_ACCEPT")))
(set! cgi-http-accept-types
(and types (separate-fields-discarding-char #\, types))))
;; HTTP_USER_AGENT format: software/version library/version.
(set! cgi-http-user-agent (getenv "HTTP_USER_AGENT")))
;;; System I/O and low-level stuff.
(define (read-n-chars num . port-arg)
(let ((p (if (null? port-arg)
(current-input-port)
(car port-arg)))
(s (make-string num)))
(do ((i 0 (+ i 1))
(ch (read-char p) (read-char p)))
((or (>= i num) (eof-object? ch)) s)
(string-set! s i ch))))
;; This is defined in #/ice-9/string-fun, but the interface is
;; weird, the semantics perverse, and it doesn't work. We use
;; a working copy here.
(define (separate-fields-discarding-char ch str)
(let loop ((fields '())
(str str))
(let ((pos (string-rindex str ch)))
(if pos
(loop (cons (substring str (+ 1 pos)) fields)
(substring str 0 pos))
(cons str fields)))))

View File

@ -1,302 +0,0 @@
;;;; http.scm: HTTP client library for Guile.
;;;;
(define-module (www http)
:use-module (www url)
:use-module (ice-9 regex))
;;;; Copyright (C) 1997 Free Software Foundation, Inc.
;;;;
;;;; This program 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 2, or (at your option)
;;;; any later version.
;;;;
;;;; This program 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 this software; see the file COPYING. If not, write to
;;;; the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
;;;; Boston, MA 02111-1307 USA
;;;;
;;; Compatibility
(or (defined? 'read-line)
(use-modules (ice-9 rdelim)))
;;; Variables that affect HTTP usage.
(define-public http:version "HTTP/1.0") ; bump up to 1.1 when ready
(define-public http:user-agent "GuileHTTP 0.1")
;;; An HTTP message is represented by a vector:
;;; #(VERSION STATUS-CODE STATUS-TEXT HEADERS BODY)
;;;
;;; Each of VERSION, STATUS-CODE, STATUS-TEXT are strings. HEADERS
;;; is an alist of headers and their contents. BODY is a single string.
(define (http:make-message version statcode stattext headers body)
(vector version statcode stattext headers body))
;;;; HTTP status predicates.
;;;
;;; (http:message-version MSG)
;;; Returns the HTTP version in use in HTTP message MSG.
;;;
;;; (http:message-status-code MSG)
;;; Returns the status code returned in HTTP message MSG.
;;;
;;; (http:message-status-text MSG)
;;; Returns the text of the status line from HTTP message MSG.
;;;
;;; (http:message-status-ok? STATUS)
;;; Returns #t if status code STATUS indicates a successful request,
;;; #f otherwise.
(define-public (http:message-version msg) (vector-ref msg 0))
(define-public (http:message-status-code msg) (vector-ref msg 1))
(define-public (http:message-status-text msg) (vector-ref msg 2))
(define-public (http:message-status-ok? msg)
(http:status-ok? (http:status-code msg)))
(define-public (http:status-ok? status)
(char=? #\2 (string-ref status 0)))
(define-public (http:message-body msg) (vector-ref msg 4))
;;; HTTP response headers functions
;;;
;;; An HTTP message header is represented here by a pair. The CAR is a
;;; symbol representing the header name, and the CDR is a string
;;; containing the header text. E.g.:
;;;
;;; '((date . "Thu, 29 May 1997 23:48:27 GMT")
;;; (server . "NCSA/1.5.1")
;;; (last-modified . "Tue, 06 May 1997 18:32:03 GMT")
;;; (content-type . "text/html")
;;; (content-length . "8097"))
;;;
;;; Note: these symbols are all lowercase, although the original headers
;;; were mixed-case. Clients using this library should keep this in
;;; mind, since Guile symbols are case-sensitive.
;;;
;;; FIXME: should headers with known semantics be parsed automatically?
;;; I.e. should the Content-Length header automatically get string->number?
;;; Should Date and Last-Modified headers be run through strptime?
;;; It is advantageous to keep headers in a uniform format, but it may
;;; be convenient to parse headers that have unambiguous meanings.
;;;
;;; (http:message-headers MSG)
;;; Returns a list of the headers from HTTP message MSG.
;;; (http:message-header HEADER MSG)
;;; Return the header field named HEADER from HTTP message MSG, or
;;; #f if no such header is present in the message.
(define-public (http:message-headers msg) (vector-ref msg 3))
(define-public (http:message-header header msg)
(http:fetch-header header (http:message-headers msg)))
(define (http:fetch-header header header-alist)
(assq-ref header-alist header))
(define header-regex (make-regexp ": *"))
(define (http:header-parse hd)
(let ((match (regexp-exec header-regex hd)))
(cons (string->symbol
(apply string
(map char-downcase
(string->list (match:prefix match)))))
(match:suffix match))))
(define (parse-status-line statline)
(let* ((first (string-index statline #\space))
(second (string-index statline #\space (1+ first))))
(list (substring statline 0 first)
(substring statline (1+ first) second)
(substring statline (1+ second)))))
;;; HTTP connection management functions.
;;;
;;; Open connections are cached on hostname in the connection-table.
;;; If an HTTP connection is already open to a particular host and TCP port,
;;; looking up the hostname and port number in connection-table will yield
;;; a Scheme port that may be used to communicate with that server.
(define connection-table '())
;; FIXME: you can only re-use a connection if the server sends the
;; Keep-Alive header, I think. With these definitions, we were trying to
;; send more requests on connections the server assumed were dead.
;; (define (add-open-connection! host tcp-port port)
;; (set! connection-table
;; (assoc-set! connection-table (cons host tcp-port) port)))
;; (define (get-open-connection host tcp-port)
;; (assoc-ref connection-table (cons host tcp-port)))
(define (add-open-connection! host tcp-port port)
#f)
(define (get-open-connection host tcp-port)
#f)
;;; HTTP methods.
;;;
;;; Common methods: GET, POST etc.
(define-public (http:get url)
;; FIXME: if http:open returns an old connection that has been
;; closed remotely, this will fail.
(http:request "GET" url))
;;; Connection-oriented functions:
;;;
;;; (http:open HOST [PORT])
;;; Return an HTTP connection to HOST on TCP port PORT (default 80).
;;; If an open connection already exists, use it; otherwise, create
;;; a new socket.
(define-public (http:open host . args)
(let ((port (cond ((null? args) 80)
((not (car args)) 80)
(else (car args)))))
(or (get-open-connection host port)
(let* ((tcp (vector-ref (getproto "tcp") 2))
(addr (car (vector-ref (gethost host) 4)))
(sock (socket AF_INET SOCK_STREAM tcp)))
(connect sock AF_INET addr port)
(add-open-connection! host port sock)
sock))))
;;; (http:request METHOD URL [HEADERS [BODY]])
;;; Submit an HTTP request.
;;; URL is a structure returned by url:parse.
;;; METHOD is the name of some HTTP method, e.g. "GET" or "POST".
;;; The optional HEADERS and BODY arguments are lists of strings
;;; which describe HTTP messages. The `Content-Length' header
;;; is calculated automatically and should not be supplied.
;;;
;;; Example usage:
;;; (http:request "get" parsed-url
;;; (list "User-Agent: GuileHTTP 0.1"
;;; "Content-Type: text/plain"))
;;; (http:request "post" parsed-url
;;; (list "User-Agent: GuileHTTP 0.1"
;;; "Content-Type: unknown/x-www-form-urlencoded")
;;; (list "search=Gosper"
;;; "case=no"
;;; "max_hits=50"))
(define-public (http:request method url . args)
(let ((host (url:host url))
(tcp-port (or (url:port url) 80))
(path (string-append "/" (or (url:path url) ""))))
(let ((sock (http:open host tcp-port))
(request (string-append method " " path " " http:version))
(headers (if (pair? args) (car args) '()))
(body (if (and (pair? args) (pair? (cdr args)))
(cadr args)
'())))
(let* ((content-length
(apply +
(map (lambda (line)
(+ 2 (string-length line))) ; + 2 for CRLF
body)))
(headers (if (positive? content-length)
(cons (string-append "Content-Length: "
(number->string content-length))
headers)
headers)))
(with-output-to-port sock
(lambda ()
(display-with-crlf request)
(for-each display-with-crlf headers)
(display "\r\n")
(for-each display-with-crlf body)))
;; parse and add status line
;; also cons up a list of response headers
(let* ((response-status-line (sans-trailing-whitespace
(read-line sock 'trim)))
(response-headers
(let make-header-list ((ln (sans-trailing-whitespace
(read-line sock 'trim)))
(hlist '()))
(if (= 0 (string-length ln))
hlist
(make-header-list (sans-trailing-whitespace
(read-line sock 'trim))
(cons (http:header-parse ln)
hlist)))))
(response-status-fields
(parse-status-line response-status-line))
(response-version (car response-status-fields))
(response-code (cadr response-status-fields))
(response-text (caddr response-status-fields)))
;; signal error if HTTP status is invalid
;; (or (http:status-ok? response-code)
;; (error 'http-status "HTTP server returned bad status"
;; response-status-line))
;; Get message body: if Content-Length header was supplied, read
;; that many chars. Otherwise, read until EOF
(let ((content-length (http:fetch-header
"content-length"
response-headers)))
(let ((response-body
(if (and content-length
(not (string-ci=? method "HEAD")))
(read-n-chars (string->number content-length) sock)
(with-output-to-string
(lambda ()
(while (not (eof-object? (peek-char sock)))
(display (read-char sock))))))))
;; FIXME: what about keepalives?
(close-port sock)
(http:make-message response-version
response-code
response-text
response-headers
response-body))))))))
;;;; System interface cruft & string funcs
(define (read-n-chars num . port-arg)
(let ((p (if (null? port-arg)
(current-input-port)
(car port-arg)))
(s (make-string num)))
(do ((i 0 (+ i 1))
(ch (read-char p) (read-char p)))
((or (>= i num) (eof-object? ch)) s)
(string-set! s i ch))))
(define (display-with-crlf line . p)
(apply display line p)
(apply display "\r\n" p))
;;; (sans-trailing-whitespace STR)
;;; These are defined in module #/ice-9/string-fun, so this code
;;; will prob. be discarded when the module system and boot-9
;;; settle down.
(define (sans-trailing-whitespace s)
(let ((st 0)
(end (string-length s)))
(while (and (< 0 end)
(char-whitespace? (string-ref s (1- end))))
(set! end (1- end)))
(if (< end st)
""
(substring s st end))))

View File

@ -1,49 +0,0 @@
;;;; www/main.scm: general WWW navigation aids.
(define-module (www main)
:use-module (www http)
:use-module (www url))
;;;; Copyright (C) 1997 Free Software Foundation, Inc.
;;;;
;;;; This program 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 2, or (at your option)
;;;; any later version.
;;;;
;;;; This program 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 this software; see the file COPYING. If not, write to
;;;; the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
;;;; Boston, MA 02111-1307 USA
;;;;
(define dispatch-table
(acons 'http http:get '()))
;;; (www:get URL)
;;; parse a URL into portions, open a connection, and retrieve
;;; selected document
(define-public (www:set-protocol-handler! proto handler)
(set! dispatch-table
(assq-set! dispatch-table proto handler)))
(define-public (www:get url-str)
(let ((url (url:parse url-str)))
;; get handler for this protocol
(case (url:scheme url)
((http) (let ((msg (http:get url)))
(http:message-body msg)))
(else
(let ((handle (assq-ref dispatch-table (url:scheme url))))
(if handle
(handle (url:host url)
(url:port url)
(url:path url))
(error "unknown URL scheme" (url:scheme url))))))))

View File

@ -1,152 +0,0 @@
;;;; url.scm: URL manipulation tools.
(define-module (www url)
:use-module (ice-9 regex))
;;;; Copyright (C) 1997 Free Software Foundation, Inc.
;;;;
;;;; This program 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 2, or (at your option)
;;;; any later version.
;;;;
;;;; This program 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 this software; see the file COPYING. If not, write to
;;;; the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
;;;; Boston, MA 02111-1307 USA
;;;;
;;;; TODO:
;;;; * support `user:password@' strings where appropriate in URLs.
;;;; * make URL parsing smarter. This is good for most TCP/IP-based
;;;; URL schemes, but parsing is actually specific to each URL scheme.
;;;; * fill out url:encode, include facilities for URL-scheme-specific
;;;; encoding methods (e.g. a url-scheme-reserved-char-alist)
;; `url:scheme' is an unfortunate term, but it is the technical
;; name for that portion of the URL according to RFC 1738. Sigh.
(define-public (url:scheme url) (vector-ref url 0))
(define-public (url:address url) (vector-ref url 1))
(define-public (url:unknown url) (vector-ref url 1))
(define-public (url:user url) (vector-ref url 1))
(define-public (url:host url) (vector-ref url 2))
(define-public (url:port url) (vector-ref url 3))
(define-public (url:path url) (vector-ref url 4))
(define-public (url:make scheme . args)
(apply vector scheme args))
(define-public (url:make-http host port path)
(vector 'http #f host port path))
(define-public (url:make-ftp user host port path)
(vector 'ftp user host port path))
(define-public (url:make-mailto address)
(vector 'mailto address))
(define http-regexp (make-regexp "^http://([^:/]+)(:([0-9]+))?(/(.*))?$"))
(define ftp-regexp
(make-regexp "^ftp://(([^@:/]+)@)?([^:/]+)(:([0-9]+))?(/(.*))?$"))
(define mailto-regexp (make-regexp "^mailto:(.*)$"))
(define-public (url:parse url)
(cond
((regexp-exec http-regexp url)
=> (lambda (m)
(url:make-http (match:substring m 1)
(cond ((match:substring m 3) => string->number)
(else #f))
(match:substring m 5))))
((regexp-exec ftp-regexp url)
=> (lambda (m)
(url:make-ftp (match:substring m 2)
(match:substring m 3)
(cond ((match:substring m 5) => string->number)
(else #f))
(match:substring m 7))))
((regexp-exec mailto-regexp url)
=> (lambda (m)
(url:make-mailto (match:substring m 1))))
(else
(url:make 'unknown url))))
(define-public (url:unparse url)
(define (pathy scheme username host port path)
(string-append (symbol->string scheme)
"://" host
(if port (string-append ":" (number->string port))
"")
(if path (string-append "/" path)
"")))
(case (url:scheme url)
((http) (pathy 'http #f
(url:host url)
(url:port url)
(url:path url)))
((ftp) (pathy 'ftp
(url:user url)
(url:host url)
(url:port url)
(url:path url)))
((mailto) (string-append "mailto:" (url:address url)))
((unknown) (url:unknown url))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; (url-decode STR)
;; Turn + into space, and hex-encoded %XX strings into their
;; eight-bit characters. Is a regexp faster than character
;; scanning? Does it incur more overhead (which may be more
;; important for code that frequently gets restarted)?
(define-public (url:decode str)
(regexp-substitute/global #f "\\+|%([0-9A-Fa-f][0-9A-Fa-f])" str
'pre
(lambda (m)
(cond ((string=? "+" (match:substring m 0)) " ")
(else (integer->char
(string->number
(match:substring m 1)
16)))))
'post))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; (url-encode STR)
;; The inverse of url-decode. Can't be done easily with
;; a regexp: we would have to construct a regular expression
;; like "[\277-\377]", for example, and Guile strings don't
;; let you interpolate character literals. Pity.
;; URL-encode any characters in STR that are not safe: these
;; include any character not in the SAFE-CHARS list and any
;; character that *is* in the RESERVED-CHARS list argument.
(define-public (url:encode str reserved-chars)
(with-output-to-string
(lambda ()
(for-each (lambda (ch)
(if (and (safe-char? ch)
(not (memv ch reserved-chars)))
(display ch)
(begin
(display #\%)
(display (number->string (char->integer ch) 16)))))
(string->list str)))))
(define safe-chars
'(#\$ #\- #\_ #\. #\+ #\! #\* #\' #\( #\) #\, #\; #\/ #\? #\: #\@ #\& #\=))
(define (safe-char? ch)
;; ``Thus, only alphanumerics, the special characters "$-_.+!*'(),", and
;; reserved characters used for their reserved purposes may be used
;; unencoded within a URL.'' RFC 1738, #2.2.
(or (char-alphabetic? ch)
(char-numeric? ch)
(memv ch safe-chars)))

View File

@ -1,28 +0,0 @@
#!/usr/local/opt/guile-cvs/bin/guile -s
!#
;;;; wwwcat: a trivial `cat' program for WWW resources.
;;;;
;;;; Copyright (C) 1997 Free Software Foundation, Inc.
;;;;
;;;; This program 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 2, or (at your option)
;;;; any later version.
;;;;
;;;; This program 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 this software; see the file COPYING. If not, write to
;;;; the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
;;;; Boston, MA 02111-1307 USA
;;;;
(use-modules (www main))
(if (program-arguments)
(display (www:get (list-ref (program-arguments) 1)))
(display "wwwget: no document specified" (current-error-port)))

23150
po/kok.po Normal file

File diff suppressed because it is too large Load Diff

22226
po/kok@latin.po Normal file

File diff suppressed because it is too large Load Diff

13914
po/lv.po

File diff suppressed because it is too large Load Diff

View File

@ -64,6 +64,7 @@ static gnc_euro_rate_struct gnc_euro_rates[] =
{ "LFR", 40.3399 }, /* luxembourg franc */
{ "LIT", 1936.27 }, /* italian lira */
{ "LUF", 40.3399 }, /* luxembourg franc */
{ "LVL", .702804 }, /* latvian lats */
{ "MTL", .429300 }, /* maltese lira */
{ "NLG", 2.20371 }, /* netherland gulden */
{ "PTA", 166.386 }, /* spanish peseta */

View File

@ -69,6 +69,7 @@ xmlNodePtr
gnc_address_to_dom_tree (const char *tag, GncAddress *addr)
{
xmlNodePtr ret;
kvp_frame *kf;
ret = xmlNewNode(NULL, BAD_CAST tag);
xmlSetProp(ret, BAD_CAST "version", BAD_CAST address_version_string);
@ -84,6 +85,16 @@ gnc_address_to_dom_tree (const char *tag, GncAddress *addr)
maybe_add_string (ret, addr_fax_string, gncAddressGetFax (addr));
maybe_add_string (ret, addr_email_string, gncAddressGetEmail (addr));
kf = qof_instance_get_slots (QOF_INSTANCE(addr));
if (kf)
{
xmlNodePtr kvpnode = kvp_frame_to_dom_tree(addr_slots_string, kf);
if (kvpnode)
{
xmlAddChild(ret, kvpnode);
}
}
return ret;
}
@ -175,7 +186,10 @@ address_email_handler (xmlNodePtr node, gpointer addr_pdata)
static gboolean
address_slots_handler (xmlNodePtr node, gpointer addr_pdata)
{
return TRUE;
struct address_pdata *pdata = addr_pdata;
return dom_tree_to_kvp_frame_given
(node, xaccAccountGetSlots (pdata->address));
}
static struct dom_tree_handler address_handlers_v2[] =

View File

@ -115,6 +115,7 @@ entry_dom_tree_create (GncEntry *entry)
GncTaxTable *taxtable;
GncOrder *order;
GncInvoice *invoice;
kvp_frame *kf;
ret = xmlNewNode(NULL, BAD_CAST gnc_entry_string);
xmlSetProp(ret, BAD_CAST "version", BAD_CAST entry_version_string);
@ -211,6 +212,16 @@ entry_dom_tree_create (GncEntry *entry)
xmlAddChild (ret, guid_to_dom_tree (entry_order_string,
qof_instance_get_guid(QOF_INSTANCE (order))));
kf = qof_instance_get_slots (QOF_INSTANCE(entry));
if (kf)
{
xmlNodePtr kvpnode = kvp_frame_to_dom_tree(entry_slots_string, kf);
if (kvpnode)
{
xmlAddChild(ret, kvpnode);
}
}
return ret;
}
@ -661,7 +672,10 @@ entry_price_handler (xmlNodePtr node, gpointer entry_pdata)
static gboolean
entry_slots_handler (xmlNodePtr node, gpointer entry_pdata)
{
return TRUE;
struct entry_pdata *pdata = entry_pdata;
return dom_tree_to_kvp_frame_given
(node, xaccAccountGetSlots (pdata->entry));
}
static struct dom_tree_handler entry_handlers_v2[] =

View File

@ -66,6 +66,7 @@ static xmlNodePtr
job_dom_tree_create (GncJob *job)
{
xmlNodePtr ret;
kvp_frame *kf;
ret = xmlNewNode(NULL, BAD_CAST gnc_job_string);
xmlSetProp(ret, BAD_CAST "version", BAD_CAST job_version_string);
@ -87,6 +88,16 @@ job_dom_tree_create (GncJob *job)
xmlAddChild(ret, int_to_dom_tree(job_active_string,
gncJobGetActive (job)));
kf = qof_instance_get_slots (QOF_INSTANCE(job));
if (kf)
{
xmlNodePtr kvpnode = kvp_frame_to_dom_tree(job_slots_string, kf);
if (kvpnode)
{
xmlAddChild(ret, kvpnode);
}
}
return ret;
}
@ -193,7 +204,10 @@ job_active_handler (xmlNodePtr node, gpointer job_pdata)
static gboolean
job_slots_handler (xmlNodePtr node, gpointer job_pdata)
{
return TRUE;
struct job_pdata *pdata = job_pdata;
return dom_tree_to_kvp_frame_given
(node, xaccAccountGetSlots (pdata->job));
}
static struct dom_tree_handler job_handlers_v2[] =

View File

@ -76,6 +76,7 @@ order_dom_tree_create (GncOrder *order)
{
xmlNodePtr ret;
Timespec ts;
kvp_frame *kf;
ret = xmlNewNode(NULL, BAD_CAST gnc_order_string);
xmlSetProp(ret, BAD_CAST "version", BAD_CAST order_version_string);
@ -102,6 +103,16 @@ order_dom_tree_create (GncOrder *order)
xmlAddChild(ret, int_to_dom_tree(order_active_string,
gncOrderGetActive (order)));
kf = qof_instance_get_slots (QOF_INSTANCE(order));
if (kf)
{
xmlNodePtr kvpnode = kvp_frame_to_dom_tree(order_slots_string, kf);
if (kvpnode)
{
xmlAddChild(ret, kvpnode);
}
}
return ret;
}
@ -234,7 +245,10 @@ order_active_handler (xmlNodePtr node, gpointer order_pdata)
static gboolean
order_slots_handler (xmlNodePtr node, gpointer order_pdata)
{
return TRUE;
struct order_pdata *pdata = order_pdata;
return dom_tree_to_kvp_frame_given
(node, xaccAccountGetSlots (pdata->order));
}
static struct dom_tree_handler order_handlers_v2[] =

View File

@ -104,6 +104,7 @@ taxtable_dom_tree_create (GncTaxTable *table)
{
xmlNodePtr ret, entries;
GList *list;
kvp_frame *kf;
ret = xmlNewNode(NULL, BAD_CAST gnc_taxtable_string);
xmlSetProp(ret, BAD_CAST "version", BAD_CAST taxtable_version_string);
@ -130,6 +131,16 @@ taxtable_dom_tree_create (GncTaxTable *table)
xmlAddChild(entries, ttentry_dom_tree_create (entry));
}
kf = qof_instance_get_slots (QOF_INSTANCE(table));
if (kf)
{
xmlNodePtr kvpnode = kvp_frame_to_dom_tree(taxtable_slots_string, kf);
if (kvpnode)
{
xmlAddChild(ret, kvpnode);
}
}
return ret;
}
@ -368,7 +379,10 @@ taxtable_entries_handler (xmlNodePtr node, gpointer taxtable_pdata)
static gboolean
taxtable_slots_handler (xmlNodePtr node, gpointer taxtable_pdata)
{
return TRUE;
struct taxtable_pdata *pdata = taxtable_pdata;
return dom_tree_to_kvp_frame_given
(node, xaccAccountGetSlots (pdata->table));
}
static struct dom_tree_handler taxtable_handlers_v2[] =

View File

@ -43,6 +43,7 @@ static gncFeature known_features[] =
{
{ GNC_FEATURE_CREDIT_NOTES, "Customer and vendor credit notes (requires at least GnuCash 2.5.0)" },
{ GNC_FEATURE_NUM_FIELD_SOURCE, "User specifies source of 'num' field'; either transaction number or split action (requires at least GnuCash 2.5.0)" },
{ GNC_FEATURE_KVP_EXTRA_DATA, "Extra data for addresses, jobs or invoice entries (requires at least GnuCash 2.6.4)" },
{ NULL },
};

View File

@ -36,11 +36,14 @@
#ifndef GNC_FEATURES_H
#define GNC_FEATURES_H
#include "libqof/qof/qof.h"
/** @name Defined features
@{
*/
#define GNC_FEATURE_CREDIT_NOTES "Credit Notes"
#define GNC_FEATURE_NUM_FIELD_SOURCE "Number Field Source"
#define GNC_FEATURE_KVP_EXTRA_DATA "Extra data in addresses, jobs or invoice entries"
/** @} */

View File

@ -32,6 +32,7 @@
#include "gncAddress.h"
#include "gncAddressP.h"
#include "gncCustomerP.h"
#include "gnc-features.h"
struct _gncAddress
{
@ -492,6 +493,10 @@ static void address_free (QofInstance *inst)
void gncAddressCommitEdit (GncAddress *addr)
{
/* GnuCash 2.6.3 and earlier didn't handle address kvp's... */
if (!kvp_frame_is_empty (addr->inst.kvp_data))
gnc_features_set_used (qof_instance_get_book (QOF_INSTANCE (addr)), GNC_FEATURE_KVP_EXTRA_DATA);
if (!qof_commit_edit (QOF_INSTANCE(addr))) return;
qof_commit_edit_part2 (&addr->inst, gncAddressOnError,
gncAddressOnDone, address_free);

View File

@ -33,6 +33,7 @@
#include "gncEntry.h"
#include "gncEntryP.h"
#include "gnc-features.h"
#include "gncInvoice.h"
#include "gncOrder.h"
@ -1505,6 +1506,10 @@ static void entry_free (QofInstance *inst)
void gncEntryCommitEdit (GncEntry *entry)
{
/* GnuCash 2.6.3 and earlier didn't handle entry kvp's... */
if (!kvp_frame_is_empty (entry->inst.kvp_data))
gnc_features_set_used (qof_instance_get_book (QOF_INSTANCE (entry)), GNC_FEATURE_KVP_EXTRA_DATA);
if (!qof_commit_edit (QOF_INSTANCE(entry))) return;
qof_commit_edit_part2 (&entry->inst, gncEntryOnError,
gncEntryOnDone, entry_free);

View File

@ -31,6 +31,7 @@
#include <glib.h>
#include <string.h>
#include "gnc-features.h"
#include "gncInvoice.h"
#include "gncJob.h"
#include "gncJobP.h"
@ -366,6 +367,10 @@ static void gncJobOnDone (QofInstance *qof) { }
void gncJobCommitEdit (GncJob *job)
{
/* GnuCash 2.6.3 and earlier didn't handle job kvp's... */
if (!kvp_frame_is_empty (job->inst.kvp_data))
gnc_features_set_used (qof_instance_get_book (QOF_INSTANCE (job)), GNC_FEATURE_KVP_EXTRA_DATA);
if (!qof_commit_edit (QOF_INSTANCE(job))) return;
qof_commit_edit_part2 (&job->inst, gncJobOnError,
gncJobOnDone, job_free);

View File

@ -30,6 +30,7 @@
#include <glib.h>
#include "gnc-features.h"
#include "gncTaxTableP.h"
struct _gncTaxTable
@ -649,6 +650,10 @@ static void table_free (QofInstance *inst)
void gncTaxTableCommitEdit (GncTaxTable *table)
{
/* GnuCash 2.6.3 and earlier didn't handle taxtable kvp's... */
if (!kvp_frame_is_empty (table->inst.kvp_data))
gnc_features_set_used (qof_instance_get_book (QOF_INSTANCE (table)), GNC_FEATURE_KVP_EXTRA_DATA);
if (!qof_commit_edit (QOF_INSTANCE(table))) return;
qof_commit_edit_part2 (&table->inst, gncTaxTableOnError,
gncTaxTableOnDone, table_free);

View File

@ -139,7 +139,7 @@
( "Loti" "loti" "sente" "ISO4217" "LSL" "426" 100 100 "M" )
( "Lithuanian Litas" "litas" "centas" "ISO4217" "LTL" "440" 100 100 "Lt" )
( "Luxembourg Franc" "frang" "centime" "ISO4217" "LUF" "442" 100 100 "Flux" ) ;; 2002-01-01 "EUR" 40.3399
( "Latvian Lats" "lats" "santīms" "ISO4217" "LVL" "428" 100 100 "Ls" )
( "Latvian Lats" "lats" "santīms" "ISO4217" "LVL" "428" 100 100 "Ls" ) ;; Valid from 2. may 2009. till 31. december 2013, now "EUR" 0.702804
( "Libyan Dinar" "dinar" "dirham" "ISO4217" "LYD" "434" 1000 1000 "ل.د" )
( "Moroccan Dirham" "dirham" "centime" "ISO4217" "MAD" "504" 100 100 "د.م" )
( "Moldovan Leu" "leu" "ban" "ISO4217" "MDL" "498" 100 100 "" )

View File

@ -135,6 +135,24 @@
(define gnc:html-barchart-subtitle
(record-accessor <html-barchart> 'subtitle))
;; Note: Due to Bug726449 the input string's non-printable control
;; characters must translated to HTML format tags BEFORE
;; or WHEN calling this function.
;; AND:
;; To ensure that the generated subtitle doesn't contain any
;; unescaped quotes or backslashes, all strings must be freed
;; from those by calling jqplot-escape-string.
;; Otherwise we're opening the gates again for bug 721768.
;;
;; Example: "\n" must be translated to "<br /> to introduce
;; a line break into the chart subtitle.
;;
;; Example call:
;; (gnc:html-barchart-set-subtitle! chart
;; (string-append "Bgt:"
;; (jqplot-escape-string (number->string bgt-sum))
;; "<br /> Act:" ;; line break in the chart sub-title
;; (jqplot-escape-string (number->string act-sum))))
(define gnc:html-barchart-set-subtitle!
(record-modifier <html-barchart> 'subtitle))
@ -452,9 +470,9 @@
(if subtitle
(begin
(push " options.title += \" (")
(push (jqplot-escape-string subtitle))
(push ")\";\n")))
(push " options.title += \" <br />")
(push subtitle)
(push "\";\n")))
(if (and (string? x-label) (> (string-length x-label) 0))
(begin

View File

@ -34,6 +34,10 @@
(gnc:module-load "gnucash/report/report-system" 0)
;; included since Bug726449
(use-modules (ice-9 regex)) ;; for regexp-substitute/global, used by jpqplot
(load-from-path "html-jqplot.scm") ;; for jqplot-escape-string
(define reportname (N_ "Budget Barchart"))
(define optname-accounts (N_ "Accounts"))
@ -153,7 +157,10 @@
(gnc:html-barchart-set-row-labels! chart date-list)
(if running-sum
(gnc:html-barchart-set-subtitle! chart
(string-append "Bgt:" (number->string bgt-sum) "\n Act:" (number->string act-sum))))
(string-append "Bgt:"
(jqplot-escape-string (number->string bgt-sum))
"<br /> Act:"
(jqplot-escape-string (number->string act-sum)))))
)
;; Reutrn newly created chart

View File

@ -35,6 +35,10 @@
(gnc:module-load "gnucash/report/report-system" 0)
;; included since Bug726449
(use-modules (ice-9 regex)) ;; for regexp-substitute/global, used by jpqplot
(load-from-path "html-jqplot.scm") ;; for jqplot-escape-string
;; The option names are defined here to 1. save typing and 2. avoid
;; spelling errors. The *reportnames* are defined here (and not only
;; once at the very end) because I need them to define the "other"
@ -454,8 +458,8 @@ developing over time"))
(if do-intervals?
(_ "%s to %s")
(_ "Balances %s to %s"))
(gnc-print-date from-date-tp)
(gnc-print-date to-date-tp)))
(jqplot-escape-string (gnc-print-date from-date-tp))
(jqplot-escape-string (gnc-print-date to-date-tp))))
(gnc:html-barchart-set-width! chart width)
(gnc:html-barchart-set-height! chart height)

View File

@ -37,6 +37,10 @@
(gnc:module-load "gnucash/report/report-system" 0)
;; included since Bug726449
(use-modules (ice-9 regex)) ;; for regexp-substitute/global, used by jpqplot
(load-from-path "html-jqplot.scm") ;; for jqplot-escape-string
(define reportname (N_ "Income/Expense Chart"))
(define optname-from-date (N_ "Start Date"))
@ -313,8 +317,8 @@
(gnc:html-barchart-set-subtitle!
chart (sprintf #f
(_ "%s to %s")
(gnc-print-date from-date-tp)
(gnc-print-date to-date-tp)))
(jqplot-escape-string (gnc-print-date from-date-tp))
(jqplot-escape-string (gnc-print-date to-date-tp))))
(gnc:html-barchart-set-width! chart width)
(gnc:html-barchart-set-height! chart height)
(gnc:html-barchart-set-row-labels! chart date-string-list)

View File

@ -31,7 +31,7 @@
(let ((chart (gnc:make-html-barchart))
(text (gnc:make-html-text (gnc:html-markup-p "[bar goes here]"))))
(gnc:html-barchart-set-title! chart "Bar Chart Title")
(gnc:html-barchart-set-subtitle! chart "Bar Chart SubTitle")
(gnc:html-barchart-set-subtitle! chart (jqplot-escape-string "Bar Chart SubTitle"))
(gnc:html-barchart-append-row! chart '(25 45 30))
(gnc:html-barchart-append-row! chart '(75 55 70))
(gnc:html-barchart-set-width! chart 320)

View File

@ -22,7 +22,6 @@
(define-module (gnucash price-quotes))
(export yahoo-get-historical-quotes)
(export gnc:book-add-quotes) ;; called from gnome/dialog-price-edit-db.c
(export gnc:price-quotes-install-sources)
@ -33,16 +32,6 @@
(gnc:module-load "gnucash/gnome-utils" 0) ;; for gnucash-ui-is-running
(gnc:module-load "gnucash/app-utils" 0)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Yahoo-based Historical Quotes
;;
(use-modules (www main))
(use-modules (srfi srfi-1))
;; (use-modules (srfi srfi-19)) when available (see below).
(define (item-list->hash! lst hash
getkey getval
hashref hashset
@ -72,171 +61,6 @@
(for-each handle-item lst)
hash)
(define (yahoo-get-historical-quotes symbol
start-year start-month start-day
end-year end-month end-day)
;; symbol must be a string naming the item of interest
;; (i.e. "LNUX"), and all the other arguments must be integers.
;; Abbreviated 2 digit years are not allowed, and months and days
;; are numbered starting with 1.
;;
;; This function returns a list of alists containing the quote data,
;; or #f on failure. Each alist will look like this:
;;
;; ((date . "21-Dec-1999")
;; (open . 108.5)
;; (high . 110.12)
;; (low . 108.06)
;; (close . 110.12)
;; (volume . 4775500))
;;
;; Note that the dates are left as strings, but the years will
;; always be 4 digits. The dates are left as strings for now
;; because without additional timezone information, it is impossible
;; to perform the conversion to UTC here. Further, it's not at all
;; clear which UTC instant each price should represent...
;;
;; NOTE: right now, we can't handle dates before 1970. That's
;; because to properly handle the fact that yahoo returns lame-ass 2
;; digit years, we need to be able to compare the dates it returns
;; using (+ year 1900) and (+ year 2000) to see which one is within
;; the star-end range requested (at least that's one of the easiest
;; ways to handle the problem). The most straightforward way to do
;; this is via mktime, but it can't handle anything before the
;; epoch. However, I believe SRFI-19 can
;; (http://srfi.schemers.org/srfi-19/srfi-19.html), so as soon as we
;; have a working implementation in guile, we can switch to that and
;; handle essentially arbitrary ranges.
;;
;; For now we'll leave in the mktime based conversion code
;; (commented out) so it'll be easy to switch later, but we'll
;; actually use a simpler (and more broken) approach -- any 2 digit
;; date >= 70 gets 1900 added, and any 2 digit date < 70 gets 2000
;; added.
; (define (str->month month-str)
; (cond
; ((string-ci=? "Jan" month-str) 1)
; ((string-ci=? "Feb" month-str) 2)
; ((string-ci=? "Mar" month-str) 3)
; ((string-ci=? "Apr" month-str) 4)
; ((string-ci=? "May" month-str) 5)
; ((string-ci=? "Jun" month-str) 6)
; ((string-ci=? "Jul" month-str) 7)
; ((string-ci=? "Aug" month-str) 8)
; ((string-ci=? "Sep" month-str) 9)
; ((string-ci=? "Oct" month-str) 10)
; ((string-ci=? "Nov" month-str) 11)
; ((string-ci=? "Dec" month-str) 12)
; (else #f)))
; (define (ymd->secs year month day)
; (let ((timevec (localtime 0)))
; (display (list 'foo year month day)) (newline)
; (set-tm:sec timevec 59)
; (set-tm:min timevec 59)
; (set-tm:hour timevec 23)
; (set-tm:mday timevec day)
; (set-tm:mon timevec (- month 1))
; (set-tm:year timevec (- year 1900))
; (set-tm:wday timevec -1)
; (set-tm:yday timevec -1)
; (set-tm:isdst timevec -1)
; (display timevec) (newline)
; (car (mktime timevec))))
; (define (fix-lame-ass-date-if-needed! quote)
; (let* ((date-str (vector-ref quote 0))
; (date-list (and date-str (string-split date-str #\-)))
; (year-str (and date-list (caddr date-list))))
; (if (= (string-length year-str) 2)
; (let* ((day (string->number (car date-list)))
; (month (str->month (cadr date-list)))
; (year (string->number year-str))
; (start-secs (ymd->secs start-year start-month start-day))
; (end-secs (ymd->secs end-year end-month end-day))
; (guess-1900 (ymd->secs (+ year 1900) month day)))
; (if (and (>= guess-1900 start-secs)
; (<= guess-1900 end-secs))
; (vector-set! quote 0 (string-append (car date-list) "-"
; (cadr date-list) "-"
; (number->string
; (+ year 1900))))
; (let ((guess-2000 (ymd->secs (+ year 2000) month day)))
; (if (and (>= guess-2000 start-secs)
; (<= guess-2000 end-secs))
; (vector-set! quote 0 (string-append (car date-list) "-"
; (cadr date-list) "-"
; (number->string
; (+ year 2000))))
; (vector-set! quote 0 #f))))))))
(define (fix-lame-ass-date-if-needed! quote-data)
(let* ((date-str (assq-ref quote-data 'date))
(date-list (and date-str (string-split date-str #\-)))
(year-str (and date-list (caddr date-list))))
(if (= (string-length year-str) 2)
(let* ((day (car date-list))
(month (cadr date-list))
(year (string->number year-str)))
(assq-set!
quote-data
'date
(string-append (car date-list) "-"
(cadr date-list) "-"
(number->string
(+ year (if (>= year 70)
1900
2000)))))))))
(define (quote-line->quote-alist line)
(let ((fields (string-split line #\,)))
(cond
((= 6 (length fields))
(map
(lambda (name value) (cons name value))
'(date open high low close volume)
(cons (car fields) (map string->number (cdr fields)))))
((zero? (string-length line))
'ignore)
(else
#f))))
(define (csv-str->quotes str)
(let ((lines (string-split str #\newline)))
(if (string=? (car lines) "Date,Open,High,Low,Close,Volume")
(let ((result (map quote-line->quote-alist (cdr lines))))
(if (any not result)
#f
(begin
(set! result
(filter (lambda (x) (not (eq? 'ignore x))) result))
(for-each fix-lame-ass-date-if-needed! result)
result)))
#f)))
(if (< start-year 1970)
#f
(let* ((request (string-append
"http://chart.yahoo.com/table.csv?"
"s=" symbol
"&a=" (number->string start-month)
"&b=" (number->string start-day)
"&c=" (number->string start-year)
"&d=" (number->string end-month)
"&e=" (number->string end-day)
"&f=" (number->string end-year)
"&g=d&q=q&y=0"))
(result (www:get request)))
(if result
(or (csv-str->quotes result)
result)
#f))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define gnc:*finance-quote-check*