summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordeva <deva>2010-06-01 12:58:32 +0000
committerdeva <deva>2010-06-01 12:58:32 +0000
commit74a28aa7125be6a603128ad600c98c4882f3b5c2 (patch)
tree1a9e4ab74f29d5ff10f2701e4e112f4525c0dcec
parent9b9c1e2dd3e5807ff7714b378b03b9ba31f42df7 (diff)
From new_protocol branch.
-rw-r--r--client/client.pro17
-rw-r--r--client/client.qrc5
-rw-r--r--client/fonts/COPYRIGHT.TXT124
-rw-r--r--client/fonts/README.TXT11
-rw-r--r--client/fonts/RELEASENOTES.TXT162
-rw-r--r--client/fonts/VeraMono.ttfbin0 -> 49224 bytes
-rw-r--r--client/icons/icon_close_commit.pngbin0 -> 1834 bytes
-rw-r--r--client/icons/icon_close_no_commit.pngbin0 -> 1520 bytes
-rw-r--r--client/icons/icon_current_sessions.pngbin0 -> 1646 bytes
-rw-r--r--client/icons/icon_discard.pngbin0 -> 1654 bytes
-rw-r--r--client/macrowindow.cc25
-rw-r--r--client/mainwindow.cc128
-rw-r--r--client/mainwindow.h18
-rw-r--r--client/netcom.cc177
-rw-r--r--client/netcom.h31
-rw-r--r--client/pracro.cc10
-rw-r--r--client/resumewidget.cc31
-rw-r--r--client/sessions.cc119
-rw-r--r--client/sessions.h58
-rw-r--r--client/viewer.cc9
-rwxr-xr-xserver/autogen.sh2
-rw-r--r--server/configure.in90
-rw-r--r--server/etc/pracrod.conf3
-rw-r--r--server/fieldnames.sql536
-rw-r--r--server/src/.cvsignore3
-rw-r--r--server/src/Makefile.am272
-rw-r--r--server/src/artefact.cc188
-rw-r--r--server/src/artefact.h54
-rw-r--r--server/src/configuration.cc18
-rw-r--r--server/src/configuration.h18
-rw-r--r--server/src/configurationparser.cc62
-rw-r--r--server/src/connection.cc339
-rw-r--r--server/src/connection.h63
-rw-r--r--server/src/connectionpool.cc162
-rw-r--r--server/src/connectionpool.h226
-rw-r--r--server/src/debug.cc2
-rw-r--r--server/src/entitylist.cc331
-rw-r--r--server/src/entitylist.h91
-rw-r--r--server/src/environment.cc85
-rw-r--r--server/src/environment.h50
-rw-r--r--server/src/inotify.cc549
-rw-r--r--server/src/inotify.h118
-rw-r--r--server/src/journal_commit.cc96
-rw-r--r--server/src/journal_commit.h33
-rw-r--r--server/src/journalwriter.cc350
-rw-r--r--server/src/journalwriter.h67
-rw-r--r--server/src/luaresume.cc30
-rw-r--r--server/src/luautil.cc312
-rw-r--r--server/src/luautil.h81
-rw-r--r--server/src/macrolist.cc83
-rw-r--r--server/src/macrolist.h41
-rw-r--r--server/src/mutex.cc76
-rw-r--r--server/src/mutex.h10
-rw-r--r--server/src/pracrod.cc53
-rw-r--r--server/src/queryhandlerpentominos.cc262
-rw-r--r--server/src/queryhandlerpentominos.h17
-rw-r--r--server/src/queryparser.cc168
-rw-r--r--server/src/queryparser.h81
-rw-r--r--server/src/resumeparser.cc3
-rw-r--r--server/src/saxparser.cc251
-rw-r--r--server/src/semaphore.cc47
-rw-r--r--server/src/semaphore.h44
-rw-r--r--server/src/server.cc462
-rw-r--r--server/src/session.cc238
-rw-r--r--server/src/session.h109
-rw-r--r--server/src/sessionparser.cc110
-rw-r--r--server/src/sessionparser.h64
-rw-r--r--server/src/sessionserialiser.cc200
-rw-r--r--server/src/sessionserialiser.h53
-rw-r--r--server/src/tcpsocket.cc34
-rw-r--r--server/src/templatelist.cc82
-rw-r--r--server/src/templatelist.h39
-rw-r--r--server/src/transactionhandler.cc287
-rw-r--r--server/src/transactionhandler.h45
-rw-r--r--server/src/transactionparser.cc148
-rw-r--r--server/src/widgetgenerator.cc28
-rw-r--r--server/xml/macros/cycloplegisk_refraktion-1.0.xml110
-rw-r--r--server/xml/macros/egen_brille-1.0.xml2
-rw-r--r--server/xml/macros/manifest_refraktion-1.0.xml110
-rw-r--r--server/xml/macros/ref-spaltelampe-1.0.xml215
-rw-r--r--server/xml/macros/ref_90d_linse-1.0.xml2
-rw-r--r--server/xml/macros/ref_aktuelle-1.0.xml3
-rw-r--r--server/xml/macros/ref_behandling-kirurgisk_procedure-1.0.xml250
-rw-r--r--server/xml/macros/ref_efterkontrol-overskrift-1.0.xml1
-rw-r--r--server/xml/macros/ref_foerstedagskontol-overskrift-1.0.xml1
-rw-r--r--server/xml/macros/ref_forunders-konklusion-1.0.xml1
-rw-r--r--server/xml/macros/test_metawidget.xml4
-rw-r--r--server/xml/macros/visus-autoref-1.0.xml4
-rw-r--r--server/xml/macros/visus-egen_korr-1.0.xml10
-rw-r--r--server/xml/macros/visus-manifest_refraktion-1.0.xml24
-rw-r--r--server/xml/macros/visus-ou-1.0.xml2
-rw-r--r--server/xml/macros/visus-template-1.0.xml16
-rw-r--r--server/xml/macros/visus-uden_korr-1.0.xml10
-rw-r--r--server/xml/templates/ref_behandling.xml2
-rw-r--r--server/xml/templates/ref_foerstedagskontrol.xml2
-rw-r--r--server/xml/templates/ref_forunders.xml2
-rw-r--r--tools/Makefile.am.test14
-rw-r--r--tools/PracroAdd16
-rwxr-xr-xtools/test5
-rw-r--r--tools/test.h262
-rwxr-xr-xtools/testlist31
101 files changed, 6820 insertions, 2470 deletions
diff --git a/client/client.pro b/client/client.pro
index f6468b4..7db485e 100644
--- a/client/client.pro
+++ b/client/client.pro
@@ -15,8 +15,7 @@ debug {
CONFIG += debug
}
-VERSION="-1.2.0"
-DEFINES+=VERSION=\\\"1.2.0\\\"
+DEFINES+=VERSION=\\\"2.0.0-beta1\\\"
win32 {
LIBPATH += lua/lib
@@ -43,6 +42,7 @@ HEADERS += \
messagebox.h \
netcom.h \
resumewidget.h \
+ sessions.h \
viewer.h \
widgetbuilder.h \
widgets.h \
@@ -78,6 +78,7 @@ SOURCES += \
messagebox.cc \
netcom.cc \
resumewidget.cc \
+ sessions.cc \
viewer.cc \
widgetbuilder.cc \
widgets/common.cc \
@@ -100,16 +101,4 @@ SOURCES += \
widgets/altcombobox.cc \
widgets/metawidget.cc
-DISTFILES += \
- icons/add.png \
- icons/arrows.png \
- icons/compressed.png \
- icons/del.png \
- icons/done.png \
- icons/icon.png \
- icons/padlock.png \
- icons/padlock.svg \
- icons/undone.png
-
-
TRANSLATIONS = pracro_dk.ts
diff --git a/client/client.qrc b/client/client.qrc
index ffbbda0..d85a872 100644
--- a/client/client.qrc
+++ b/client/client.qrc
@@ -9,5 +9,10 @@
<file>icons/padlock.png</file>
<file>icons/done.png</file>
<file>icons/undone.png</file>
+ <file>icons/icon_close_commit.png</file>
+ <file>icons/icon_current_sessions.png</file>
+ <file>icons/icon_close_no_commit.png</file>
+ <file>icons/icon_discard.png</file>
+ <file>fonts/VeraMono.ttf</file>
</qresource>
</RCC>
diff --git a/client/fonts/COPYRIGHT.TXT b/client/fonts/COPYRIGHT.TXT
new file mode 100644
index 0000000..e651be1
--- /dev/null
+++ b/client/fonts/COPYRIGHT.TXT
@@ -0,0 +1,124 @@
+Bitstream Vera Fonts Copyright
+
+The fonts have a generous copyright, allowing derivative works (as
+long as "Bitstream" or "Vera" are not in the names), and full
+redistribution (so long as they are not *sold* by themselves). They
+can be be bundled, redistributed and sold with any software.
+
+The fonts are distributed under the following copyright:
+
+Copyright
+=========
+
+Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream
+Vera is a trademark of Bitstream, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the fonts accompanying this license ("Fonts") and associated
+documentation files (the "Font Software"), to reproduce and distribute
+the Font Software, including without limitation the rights to use,
+copy, merge, publish, distribute, and/or sell copies of the Font
+Software, and to permit persons to whom the Font Software is furnished
+to do so, subject to the following conditions:
+
+The above copyright and trademark notices and this permission notice
+shall be included in all copies of one or more of the Font Software
+typefaces.
+
+The Font Software may be modified, altered, or added to, and in
+particular the designs of glyphs or characters in the Fonts may be
+modified and additional glyphs or characters may be added to the
+Fonts, only if the fonts are renamed to names not containing either
+the words "Bitstream" or the word "Vera".
+
+This License becomes null and void to the extent applicable to Fonts
+or Font Software that has been modified and is distributed under the
+"Bitstream Vera" names.
+
+The Font Software may be sold as part of a larger software package but
+no copy of one or more of the Font Software typefaces may be sold by
+itself.
+
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL
+BITSTREAM OR THE GNOME FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL,
+OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT
+SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE.
+
+Except as contained in this notice, the names of Gnome, the Gnome
+Foundation, and Bitstream Inc., shall not be used in advertising or
+otherwise to promote the sale, use or other dealings in this Font
+Software without prior written authorization from the Gnome Foundation
+or Bitstream Inc., respectively. For further information, contact:
+fonts at gnome dot org.
+
+Copyright FAQ
+=============
+
+ 1. I don't understand the resale restriction... What gives?
+
+ Bitstream is giving away these fonts, but wishes to ensure its
+ competitors can't just drop the fonts as is into a font sale system
+ and sell them as is. It seems fair that if Bitstream can't make money
+ from the Bitstream Vera fonts, their competitors should not be able to
+ do so either. You can sell the fonts as part of any software package,
+ however.
+
+ 2. I want to package these fonts separately for distribution and
+ sale as part of a larger software package or system. Can I do so?
+
+ Yes. A RPM or Debian package is a "larger software package" to begin
+ with, and you aren't selling them independently by themselves.
+ See 1. above.
+
+ 3. Are derivative works allowed?
+ Yes!
+
+ 4. Can I change or add to the font(s)?
+ Yes, but you must change the name(s) of the font(s).
+
+ 5. Under what terms are derivative works allowed?
+
+ You must change the name(s) of the fonts. This is to ensure the
+ quality of the fonts, both to protect Bitstream and Gnome. We want to
+ ensure that if an application has opened a font specifically of these
+ names, it gets what it expects (though of course, using fontconfig,
+ substitutions could still could have occurred during font
+ opening). You must include the Bitstream copyright. Additional
+ copyrights can be added, as per copyright law. Happy Font Hacking!
+
+ 6. If I have improvements for Bitstream Vera, is it possible they might get
+ adopted in future versions?
+
+ Yes. The contract between the Gnome Foundation and Bitstream has
+ provisions for working with Bitstream to ensure quality additions to
+ the Bitstream Vera font family. Please contact us if you have such
+ additions. Note, that in general, we will want such additions for the
+ entire family, not just a single font, and that you'll have to keep
+ both Gnome and Jim Lyles, Vera's designer, happy! To make sense to add
+ glyphs to the font, they must be stylistically in keeping with Vera's
+ design. Vera cannot become a "ransom note" font. Jim Lyles will be
+ providing a document describing the design elements used in Vera, as a
+ guide and aid for people interested in contributing to Vera.
+
+ 7. I want to sell a software package that uses these fonts: Can I do so?
+
+ Sure. Bundle the fonts with your software and sell your software
+ with the fonts. That is the intent of the copyright.
+
+ 8. If applications have built the names "Bitstream Vera" into them,
+ can I override this somehow to use fonts of my choosing?
+
+ This depends on exact details of the software. Most open source
+ systems and software (e.g., Gnome, KDE, etc.) are now converting to
+ use fontconfig (see www.fontconfig.org) to handle font configuration,
+ selection and substitution; it has provisions for overriding font
+ names and subsituting alternatives. An example is provided by the
+ supplied local.conf file, which chooses the family Bitstream Vera for
+ "sans", "serif" and "monospace". Other software (e.g., the XFree86
+ core server) has other mechanisms for font substitution.
+
diff --git a/client/fonts/README.TXT b/client/fonts/README.TXT
new file mode 100644
index 0000000..0f71795
--- /dev/null
+++ b/client/fonts/README.TXT
@@ -0,0 +1,11 @@
+Contained herin is the Bitstream Vera font family.
+
+The Copyright information is found in the COPYRIGHT.TXT file (along
+with being incoporated into the fonts themselves).
+
+The releases notes are found in the file "RELEASENOTES.TXT".
+
+We hope you enjoy Vera!
+
+ Bitstream, Inc.
+ The Gnome Project
diff --git a/client/fonts/RELEASENOTES.TXT b/client/fonts/RELEASENOTES.TXT
new file mode 100644
index 0000000..270bc0d
--- /dev/null
+++ b/client/fonts/RELEASENOTES.TXT
@@ -0,0 +1,162 @@
+Bitstream Vera Fonts - April 16, 2003
+=====================================
+
+The version number of these fonts is 1.10 to distinguish them from the
+beta test fonts.
+
+Note that the Vera copyright is incorporated in the fonts themselves.
+The License field in the fonts contains the copyright license as it
+appears below. The TrueType copyright field is not large enough to
+contain the full license, so the license is incorporated (as you might
+think if you thought about it) into the license field, which
+unfortunately can be obscure to find. (In pfaedit, see: Element->Font
+Info->TTFNames->License).
+
+Our apologies for it taking longer to complete the fonts than planned.
+Beta testers requested a tighter line spacing (less leading) and Jim
+Lyles redesigned Vera's accents to bring its line spacing to more
+typical of other fonts. This took additional time and effort. Our
+thanks to Jim for this effort above and beyond the call of duty.
+
+There are four monospace and sans faces (normal, oblique, bold, bold
+oblique) and two serif faces (normal and bold). Fontconfig/Xft2 (see
+www.fontconfig.org) can artificially oblique the serif faces for you:
+this loses hinting and distorts the faces slightly, but is visibly
+different than normal and bold, and reasonably pleasing.
+
+On systems with fontconfig 2.0 or 2.1 installed, making your sans,
+serif and monospace fonts default to these fonts is very easy. Just
+drop the file local.conf into your /etc/fonts directory. This will
+make the Bitstream fonts your default fonts for all applications using
+fontconfig (if sans, serif, or monospace names are used, as they often
+are as default values in many desktops). The XML in local.conf may
+need modification to enable subpixel decimation, if appropriate,
+however, the commented out phrase does so for XFree86 4.3, in the case
+that the server does not have sufficient information to identify the
+use of a flat panel. Fontconfig 2.2 adds Vera to the list of font
+families and will, by default use it as the default sans, serif and
+monospace fonts.
+
+During the testing of the final Vera fonts, we learned that screen
+fonts in general are only typically hinted to work correctly at
+integer pixel sizes. Vera is coded internally for integer sizes only.
+We need to investigate further to see if there are commonly used fonts
+that are hinted to be rounded but are not rounded to integer sizes due
+to oversights in their coding.
+
+Most fonts work best at 8 pixels and below if anti-aliased only, as
+the amount of work required to hint well at smaller and smaller sizes
+becomes astronomical. GASP tables are typically used to control
+whether hinting is used or not, but Freetype/Xft does not currently
+support GASP tables (which are present in Vera).
+
+To mitigate this problem, both for Vera and other fonts, there will be
+(very shortly) a new fontconfig 2.2 release that will, by default not
+apply hints if the size is below 8 pixels. if you should have a font
+that in fact has been hinted more agressively, you can use fontconfig
+to note this exception. We believe this should improve many hinted
+fonts in addition to Vera, though implemeting GASP support is likely
+the right long term solution.
+
+Font rendering in Gnome or KDE is the combination of algorithms in
+Xft2 and Freetype, along with hinting in the fonts themselves. It is
+vital to have sufficient information to disentangle problems that you
+may observe.
+
+Note that having your font rendering system set up correctly is vital
+to proper judgement of problems of the fonts:
+
+ * Freetype may or may not be configured to in ways that may
+ implement execution of possibly patented (in some parts of the world)
+ TrueType hinting algorithms, particularly at small sizes. Best
+ results are obtained while using these algorithms.
+
+ * The freetype autohinter (used when the possibly patented
+ algorithms are not used) continues to improve with each release. If
+ you are using the autohinter, please ensure you are using an up to
+ date version of freetype before reporting problems.
+
+ * Please identify what version of freetype you are using in any
+ bug reports, and how your freetype is configured.
+
+ * Make sure you are not using the freetype version included in
+ XFree86 4.3, as it has bugs that significantly degrade most fonts,
+ including Vera. if you build XFree86 4.3 from source yourself, you may
+ have installed this broken version without intending it (as I
+ did). Vera was verified with the recently released Freetype 2.1.4. On
+ many systems, 'ldd" can be used to see which freetype shared library
+ is actually being used.
+
+ * Xft/X Render does not (yet) implement gamma correction. This
+ causes significant problems rendering white text on a black background
+ (causing partial pixels to be insufficiently shaded) if the gamma of
+ your monitor has not been compensated for, and minor problems with
+ black text on a while background. The program "xgamma" can be used to
+ set a gamma correction value in the X server's color pallette. Most
+ monitors have a gamma near 2.
+
+ * Note that the Vera family uses minimal delta hinting. Your
+ results on other systems when not used anti-aliased may not be
+ entirely satisfying. We are primarily interested in reports of
+ problems on open source systems implementing Xft2/fontconfig/freetype
+ (which implements antialiasing and hinting adjustements, and
+ sophisticated subpixel decimation on flatpanels). Also, the
+ algorithms used by Xft2 adjust the hints to integer widths and the
+ results are crisper on open source systems than on Windows or
+ MacIntosh.
+
+ * Your fontconfig may (probably does) predate the release of
+ fontconfig 2.2, and you may see artifacts not present when the font is
+ used at very small sizes with hinting enabled. "vc-list -V" can be
+ used to see what version you have installed.
+
+We believe and hope that these fonts will resolve the problems
+reported during beta test. The largest change is the reduction of
+leading (interline spacing), which had annoyed a number of people, and
+reduced Vera's utility for some applcations. The Vera monospace font
+should also now make '0' and 'O' and '1' and 'l' more clearly
+distinguishable.
+
+The version of these fonts is version 1.10. Fontconfig should be
+choosing the new version of the fonts if both the released fonts and
+beta test fonts are installed (though please discard them: they have
+names of form tt20[1-12]gn.ttf). Note that older versions of
+fontconfig sometimes did not rebuild their cache correctly when new
+fonts are installed: please upgrade to fontconfig 2.2. "fc-cache -f"
+can be used to force rebuilding fontconfig's cache files.
+
+If you note problems, please send them to fonts at gnome dot org, with
+exactly which face and size and unicode point you observe the problem
+at. The xfd utility from XFree86 CVS may be useful for this (e.g. "xfd
+-fa sans"). A possibly more useful program to examine fonts at a
+variety of sizes is the "waterfall" program found in Keith Packard's
+CVS.
+
+ $ cvs -d :pserver:anoncvs@keithp.com:/local/src/CVS login
+ Logging in to :pserver:anoncvs@keithp.com:2401/local/src/CVS
+ CVS password: <hit return>
+ $ cvs -d :pserver:anoncvs@keithp.com:/local/src/CVS co waterfall
+ $ cd waterfall
+ $ xmkmf -a
+ $ make
+ # make install
+ # make install.man
+
+Again, please make sure you are running an up-to-date freetype, and
+that you are only examining integer sizes.
+
+Reporting Problems
+==================
+
+Please send problem reports to fonts at gnome org, with the following
+information:
+
+ 1. Version of Freetype, Xft2 and fontconfig
+ 2. Whether TT hinting is being used, or the autohinter
+ 3. Application being used
+ 4. Character/Unicode code point that has problems (if applicable)
+ 5. Version of which operating system
+ 6. Please include a screenshot, when possible.
+
+Please check the fonts list archives before reporting problems to cut
+down on duplication.
diff --git a/client/fonts/VeraMono.ttf b/client/fonts/VeraMono.ttf
new file mode 100644
index 0000000..139f0b4
--- /dev/null
+++ b/client/fonts/VeraMono.ttf
Binary files differ
diff --git a/client/icons/icon_close_commit.png b/client/icons/icon_close_commit.png
new file mode 100644
index 0000000..2da7b33
--- /dev/null
+++ b/client/icons/icon_close_commit.png
Binary files differ
diff --git a/client/icons/icon_close_no_commit.png b/client/icons/icon_close_no_commit.png
new file mode 100644
index 0000000..70e5492
--- /dev/null
+++ b/client/icons/icon_close_no_commit.png
Binary files differ
diff --git a/client/icons/icon_current_sessions.png b/client/icons/icon_current_sessions.png
new file mode 100644
index 0000000..6881af2
--- /dev/null
+++ b/client/icons/icon_current_sessions.png
Binary files differ
diff --git a/client/icons/icon_discard.png b/client/icons/icon_discard.png
new file mode 100644
index 0000000..5cfa574
--- /dev/null
+++ b/client/icons/icon_discard.png
Binary files differ
diff --git a/client/macrowindow.cc b/client/macrowindow.cc
index 98262fd..d9060b0 100644
--- a/client/macrowindow.cc
+++ b/client/macrowindow.cc
@@ -151,11 +151,26 @@ bool MacroWindow::doCommit()
// If all entries passed validation, continue commit
if(faulty == 0) {
- netcom.send(widgets, templ, macro, version);
+ QDomDocument doc = netcom.send(widgets, templ, macro, version);
+
+ QDomNodeList nl = doc.documentElement().childNodes();
+ QDomNode n = nl.at(0); // There can be only one! (Swush, flomp)
+
+ if(n.toElement().tagName() == "error") {
+ QMessageBox::critical(this, "Server Error", "Server Error: " +
+ n.toElement().text());
+ return false;
+ }
+
emit updateOnCommit();
setCollapsed(true);
return true;
} else {
+ MessageBox::critical(NULL, "Fejl",
+ "Makroen " + macrotitle +
+ " er ikke udfyldt korrekt, prøv igen.\n",
+ MessageBox::Ok);
+
return false;
}
}
@@ -168,13 +183,7 @@ void MacroWindow::close()
void MacroWindow::commit()
{
- if(doCommit()) {
- // close();
- } else {
- MessageBox::critical(NULL, "Fejl",
- "Makroen " + macrotitle + " er ikke udfyldt korrekt, prøv igen.\n",
- MessageBox::Ok);
- }
+ doCommit();
}
void MacroWindow::reset()
diff --git a/client/mainwindow.cc b/client/mainwindow.cc
index 51bb772..3d49752 100644
--- a/client/mainwindow.cc
+++ b/client/mainwindow.cc
@@ -37,20 +37,50 @@
#include <QScrollArea>
#include <QSettings>
#include <QStatusBar>
+#include <QMessageBox>
+#include <QToolBar>
+#include <QAction>
#include "macrodrawer.h"
-MainWindow::MainWindow(QString cpr, QString templ, QString host, quint16 port, QString user)
+MainWindow::MainWindow(QString cpr, QString templ, QString host,
+ quint16 port, QString user)
: QMainWindow(0, Qt::WindowContextHelpButtonHint),
- netcom(host, port, user, cpr)
+ netcom(host, port)
{
+ isStored = false;
+
header = NULL;
+ this->cpr = cpr;
+ this->user = user;
+
setWindowTitle("Pracro - " + cpr);
QStatusBar *status = statusBar();
status->addPermanentWidget(new QLabel("Pracro v."VERSION));
+ QToolBar *toolbar = addToolBar("controls");
+ toolbar->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
+ QAction *close_commit = toolbar->addAction("Close and commit");
+ close_commit->setIcon(QPixmap(":icons/icon_close_commit.png"));
+
+ QAction *close_no_commit = toolbar->addAction("Close no commit");
+ close_no_commit->setIcon(QPixmap(":icons/icon_close_no_commit.png"));
+ /*
+ QAction *close_discard = toolbar->addAction("Close discard");
+ close_discard->setIcon(QPixmap(":icons/icon_discard.png"));
+ connect(close_discard, SIGNAL(triggered()), this, SLOT(closeDiscard()));
+ */
+ toolbar->addSeparator();
+
+ QAction *show_sessions = toolbar->addAction("Show sessions");
+ show_sessions->setIcon(QPixmap(":icons/icon_current_sessions.png"));
+
+ connect(close_commit, SIGNAL(triggered()), this, SLOT(closeCommit()));
+ connect(close_no_commit, SIGNAL(triggered()), this, SLOT(closeNoCommit()));
+ connect(show_sessions, SIGNAL(triggered()), this, SLOT(showSessions()));
+
QScrollArea *s = new QScrollArea();
setCentralWidget(s);
w = new QWidget();
@@ -61,24 +91,77 @@ MainWindow::MainWindow(QString cpr, QString templ, QString host, quint16 port, Q
this->templ = templ;
setStatusBar(status);
-
+
init();
+
+ if(sessions.isEmpty()) {
+ show_sessions->setEnabled(false);
+ }
}
MainWindow::~MainWindow()
{
}
-void MainWindow::closeEvent(QCloseEvent *)
+void MainWindow::closeCommit()
{
- QSettings settings("Aasimon.org", "Pracro");
+ netcom.commit();
+ sessions.remove(cpr);
+ isStored = true;
+ close();
+}
- settings.beginGroup("MainWindow");
- settings.setValue("size", size());
- settings.setValue("pos", pos());
- settings.endGroup();
+void MainWindow::closeNoCommit()
+{
+ QMessageBox::information(this,
+ "Closing without commit",
+ "This session will be stored on this computer only."
+ " To reopen it at a later time, simply open the same patient again.");
+ sessions.add(cpr, user, netcom.sessionid);
+ isStored = true;
+ close();
+}
- QApplication::quit();
+void MainWindow::closeDiscard()
+{
+ if(QMessageBox::question(this,
+ "Discard",
+ "This session will <strong>NOT</strong> be stored in the journal.<br/>"
+ "Are you sure you want to continue?",
+ QMessageBox::Yes | QMessageBox::No)
+ == QMessageBox::Yes) {
+ netcom.discard();
+ sessions.remove(cpr);
+ isStored = true;
+ close();
+ }
+}
+
+void MainWindow::showSessions()
+{
+ sessions.show();
+}
+
+void MainWindow::closeEvent(QCloseEvent *event)
+{
+ if(isStored || QMessageBox::question(this,
+ "Discard",
+ "This session will <strong>NOT</strong> be stored in the journal.<br/>"
+ "Are you sure you want to continue?",
+ QMessageBox::Yes | QMessageBox::No)
+ == QMessageBox::Yes) {
+ QSettings settings("Aasimon.org", "Pracro");
+
+ settings.beginGroup("MainWindow");
+ settings.setValue("size", size());
+ settings.setValue("pos", pos());
+ settings.setValue(QString("sessions"), sessions.toVariant());
+ settings.endGroup();
+
+ event->accept();
+ } else {
+ event->ignore();
+ }
}
void MainWindow::init()
@@ -88,8 +171,21 @@ void MainWindow::init()
settings.beginGroup("MainWindow");
resize(settings.value("size", QSize(700, 800)).toSize());
move(settings.value("pos", QPoint(0, 0)).toPoint());
+ sessions.fromVariant(settings.value("sessions"));
settings.endGroup();
+ netcom.patientid = cpr;
+ netcom.user = user;
+
+ if(sessions.contains(cpr)) {
+ netcom.sessionid = sessions.getSessionID(cpr);
+ if(sessions.getUser(cpr) != user) {
+ // What to do? We are running an old session with a new user!
+ }
+ }
+
+ netcom.initConnection();
+
initialising = true;
update();
initialising = false;
@@ -112,7 +208,8 @@ void MainWindow::updateTemplateHeaders(QDomNode templatenode)
w->layout()->addWidget(header);
}
- statusBar()->showMessage(template_title + " (" + template_name + ")");
+ statusBar()->showMessage(template_title + " (" + template_name +
+ ") - SessionID: " + netcom.sessionid);
}
@@ -122,6 +219,13 @@ void MainWindow::update()
QDomNodeList templates = xml_doc.documentElement().childNodes();
QDomNode templatenode = templates.at(0); // There can be only one! (Swush, flomp)
+
+ if(templatenode.toElement().tagName() == "error") {
+ QMessageBox::critical(this, "Error",
+ templatenode.toElement().text());
+ return;
+ }
+
updateTemplateHeaders(templatenode);
@@ -142,7 +246,7 @@ void MainWindow::update()
i++;
}
- // if(found == false || macroelement.hasAttribute("header")) {
+ // if(found == false || macroelement.hasAttribute("header")) {
if(found == false || macroelement.tagName() == "header") {
QString num;
num.sprintf("%04d", j);
diff --git a/client/mainwindow.h b/client/mainwindow.h
index e19b070..afc9d08 100644
--- a/client/mainwindow.h
+++ b/client/mainwindow.h
@@ -31,21 +31,28 @@
#include <QMap>
#include <QVector>
#include <QPushButton>
+#include <QFont>
+
#include "netcom.h"
#include "macrowindow.h"
-
+#include "sessions.h"
#include "macro.h"
class MainWindow : public QMainWindow {
Q_OBJECT
public:
- MainWindow(QString cpr, QString templ, QString host, quint16 port, QString user);
+ MainWindow(QString cpr, QString templ, QString host, quint16 port,
+ QString user);
~MainWindow();
void closeEvent(QCloseEvent *event);
public slots:
void update();
+ void closeCommit();
+ void closeNoCommit();
+ void closeDiscard();
+ void showSessions();
private:
void updateTemplateHeaders(QDomNode templatenode);
@@ -53,6 +60,9 @@ private:
QString templ;
NetCom netcom;
+ QString cpr;
+ QString user;
+
// QMap< QString, MacroWindow* > macros;
Macros macros;
QWidget *w;
@@ -61,7 +71,11 @@ private:
bool initialising;
+ Sessions sessions;
+
void init();
+
+ bool isStored;
};
#endif/*__PRACRO_MAINWINDOW_H__*/
diff --git a/client/netcom.cc b/client/netcom.cc
index 3b3abb7..97f9ee1 100644
--- a/client/netcom.cc
+++ b/client/netcom.cc
@@ -26,64 +26,95 @@
*/
#include "netcom.h"
+#include <QtNetwork>
+
#include <QApplication>
#include <QByteArray>
+#include <QHttp>
+
#include "widgets/widget.h"
-NetCom::NetCom(QString host, quint16 port, QString user, QString cpr)
+#ifdef USE_SSL
+#include <QMessageBox>
+#include <QList>
+#include <QSslError>
+#include <QSslSocket>
+
+#ifdef QT_NO_OPENSSL
+#error "QT not compiled with SSL support."
+#endif
+#endif
+
+NetCom::NetCom(QString host, quint16 port)
{
- this->user = user;
- this->cpr = cpr;
- socket.connectToHost(host, port);
- connect(&socket, SIGNAL(readyRead()), this, SLOT(readyRead()));
- socket.waitForConnected();
- transmitting = false;
+ //
+ // Setup connection
+ //
+ QUrl url;
+ url.setHost(host);
+ url.setPort(port);
+ url.setScheme("http");
+ // url.setScheme("https");
+
+ request.setUrl(url);
+
+ manager = new QNetworkAccessManager(this);
+ connect(manager, SIGNAL(finished(QNetworkReply*)),
+ this, SLOT(replyFinished(QNetworkReply*)));
}
NetCom::~NetCom()
{
- socket.disconnectFromHost();
+ //
+ // Clean up
+ //
+ delete manager;
}
-QDomDocument NetCom::send(QString templ, QString macro, bool lockgui)
+void NetCom::replyFinished(QNetworkReply *reply)
+{
+ finished[reply] = true;
+}
+
+QDomDocument NetCom::makeTransfer(QDomDocument &doc,
+ bool commit, bool lockgui, bool discard)
{
- printf("Socket state: %d\n", socket.state());
- if(socket.state() != 3) printf("Socket state not connected: %s\n", socket.errorString().toStdString().c_str());
+ printf("\nMaking transfer:\n%s", doc.toString().toStdString().c_str());
if(lockgui && qApp->activeWindow()) qApp->activeWindow()->setEnabled(false);
if(lockgui) QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
- QDomDocument doc;
-
- QDomProcessingInstruction header = doc.createProcessingInstruction("xml", "version='1.0' encoding='UTF-8'");
- doc.appendChild(header);
-
- QDomElement pracro_elem = doc.createElement("pracro");
- pracro_elem.setAttribute("version", "1.0");
- pracro_elem.setAttribute("cpr", cpr);
- pracro_elem.setAttribute("user", user);
- doc.appendChild(pracro_elem);
+ if(sessionid != "") request.setRawHeader("SessionID",
+ sessionid.toStdString().c_str());
+ if(commit) {
+ request.setRawHeader("SessionCommit", "yes");
+ }
- QDomElement request_elem = doc.createElement("request");
- request_elem.setAttribute("template", templ);
- if(macro != "") request_elem.setAttribute("macro", macro);
- pracro_elem.appendChild(request_elem);
-
- printf("\nSending request:\n%s", doc.toString().toStdString().c_str());
+ if(discard) {
+ request.setRawHeader("SessionDiscard", "yes");
+ }
- socket.write(doc.toByteArray());
- // socket.waitForReadyRead();
+ // QNetworkReply *reply = manager->get(request);
+ QNetworkReply *reply = manager->post(request, doc.toByteArray());
+ finished[reply] = false;
+ while(finished[reply] == false) {
+ qApp->processEvents(QEventLoop::WaitForMoreEvents, 100);
+ }
+ finished.remove(reply);
- do {
- qApp->processEvents(QEventLoop::WaitForMoreEvents);
- } while(!res_doc.setContent(buffer));
+ QByteArray data = reply->readAll();
+ QDomDocument res_doc;
+ res_doc.setContent(data);
- buffer = "";
+ printf("\nRecieved reponse:\n%s", data.data());
- QDomElement elem = res_doc.documentElement();
+ printf("\nRecieved reponse (Parsed):\n%s", res_doc.toByteArray().data());
- printf("\nRecieved request:\n%s", res_doc.toString().toStdString().c_str());
+ if(reply->hasRawHeader("SessionID")) {
+ sessionid = reply->rawHeader("SessionID");
+ printf("SESSION ID: %s\n", sessionid.toStdString().c_str());
+ }
if(lockgui) QApplication::restoreOverrideCursor();
if(lockgui && qApp->activeWindow()) qApp->activeWindow()->setEnabled(true);
@@ -91,26 +122,58 @@ QDomDocument NetCom::send(QString templ, QString macro, bool lockgui)
return res_doc;
}
-void NetCom::readyRead()
+QDomDocument NetCom::initConnection()
{
- buffer.append(socket.readAll());
+ QDomDocument doc;
+ return makeTransfer(doc, false, true);
}
-void NetCom::send(QVector< Widget* > widgets, QString templ, QString macro, QString version)
+QDomDocument NetCom::commit()
{
- printf("Socket state: %d\n", socket.state());
- if(socket.state() != 3) printf("Socket state not connected: %s\n", socket.errorString().toStdString().c_str());
+ QDomDocument doc;
+ return makeTransfer(doc, true, true);
+}
- // if(qApp->activeWindow()) qApp->activeWindow()->setEnabled(false); // Moved down!
+QDomDocument NetCom::discard()
+{
+ QDomDocument doc;
+ return makeTransfer(doc, false, true, true);
+}
+
+QDomDocument NetCom::send(QString templ, QString macro, bool lockgui)
+{
+ QDomDocument doc;
+
+ QDomProcessingInstruction header =
+ doc.createProcessingInstruction("xml", "version='1.0' encoding='UTF-8'");
+ doc.appendChild(header);
+
+ QDomElement pracro_elem = doc.createElement("pracro");
+ pracro_elem.setAttribute("version", "1.0");
+ pracro_elem.setAttribute("cpr", patientid);
+ pracro_elem.setAttribute("user", user);
+ doc.appendChild(pracro_elem);
+
+ QDomElement request_elem = doc.createElement("request");
+ request_elem.setAttribute("template", templ);
+ if(macro != "") request_elem.setAttribute("macro", macro);
+ pracro_elem.appendChild(request_elem);
+
+ return makeTransfer(doc, false, lockgui);
+}
+QDomDocument NetCom::send(QVector< Widget* > widgets, QString templ,
+ QString macro, QString version)
+{
QDomDocument doc;
- QDomProcessingInstruction header = doc.createProcessingInstruction("xml", "version='1.0' encoding='UTF-8'");
+ QDomProcessingInstruction header =
+ doc.createProcessingInstruction("xml", "version='1.0' encoding='UTF-8'");
doc.appendChild(header);
QDomElement pracro_elem = doc.createElement("pracro");
pracro_elem.setAttribute("version", "1.0");
- pracro_elem.setAttribute("cpr", cpr);
+ pracro_elem.setAttribute("cpr", patientid);
pracro_elem.setAttribute("user", user);
doc.appendChild(pracro_elem);
@@ -120,7 +183,8 @@ void NetCom::send(QVector< Widget* > widgets, QString templ, QString macro, QStr
commit_elem.setAttribute("version", version);
pracro_elem.appendChild(commit_elem);
- // Iterate the different entries, and append their results to the commit string
+ // Iterate the different entries, and append their results to
+ // the commit string
QVector< Widget* >::iterator i = widgets.begin();
while (i != widgets.end()) {
Widget* w = *i;
@@ -134,27 +198,6 @@ void NetCom::send(QVector< Widget* > widgets, QString templ, QString macro, QStr
i++;
}
-
- if(qApp->activeWindow()) qApp->activeWindow()->setEnabled(false);
-
- printf("\nSending commit:\n%s", doc.toString().toStdString().c_str());
-
- socket.write(doc.toByteArray());
- // socket.waitForReadyRead();
-
- //
- // Wait for the (hopefully) empty answer.
- //
- do {
- qApp->processEvents(QEventLoop::WaitForMoreEvents);
- } while(!res_doc.setContent(buffer));
-
- buffer = "";
-
- //QDomElement elem = res_doc.documentElement();
-
- printf("\nRecieved commit:\n%s", res_doc.toString().toStdString().c_str());
-
- QApplication::restoreOverrideCursor();
- if(qApp->activeWindow()) qApp->activeWindow()->setEnabled(true);
+
+ return makeTransfer(doc, false, true);
}
diff --git a/client/netcom.h b/client/netcom.h
index 35db221..88b604e 100644
--- a/client/netcom.h
+++ b/client/netcom.h
@@ -31,6 +31,10 @@
#include <QString>
#include <QTcpSocket>
#include <QDomDocument>
+#include <QNetworkAccessManager>
+#include <QNetworkRequest>
+
+//#define USE_SSL
//#include "widgets/widget.h"
class Widget;
@@ -38,24 +42,33 @@ class Widget;
class NetCom : public QObject {
Q_OBJECT
public:
- NetCom(QString host, quint16 port, QString user, QString cpr);
+ NetCom(QString host, quint16 port);
~NetCom();
QDomDocument send(QString templ, QString macro = "", bool lockgui = true);
- void send(QVector< Widget* > widgets, QString templ, QString macro, QString version);
+ QDomDocument send(QVector< Widget* > widgets, QString templ, QString macro,
+ QString version);
+ QDomDocument initConnection();
+ QDomDocument commit();
+ QDomDocument discard();
+
+ QString sessionid;
+ QString user;
+ QString patientid;
public slots:
- void readyRead();
+ void replyFinished(QNetworkReply*);
private:
- volatile bool transmitting;
- QTcpSocket socket;
+ QNetworkAccessManager *manager;
+ QNetworkRequest request;
- QByteArray buffer;
- QDomDocument res_doc;
+ // QString sessionid;
- QString user;
- QString cpr;
+ QMap<QNetworkReply *, bool> finished;
+
+ QDomDocument makeTransfer(QDomDocument &dom,
+ bool commit, bool lockgui, bool discard = false);
};
#endif/*__PRACRO_NETCOM_H__*/
diff --git a/client/pracro.cc b/client/pracro.cc
index 37b1399..bb2d952 100644
--- a/client/pracro.cc
+++ b/client/pracro.cc
@@ -34,6 +34,9 @@
#include <QTranslator>
+#include <QFontDatabase>
+#include <QFont>
+
#include "netcom.h"
#include "mainwindow.h"
#include "viewer.h"
@@ -50,6 +53,8 @@ QString config = CONFIG_DEFAULT;
QString host;
quint16 port;
+QFont *fixedfont;
+
static void print_usage()
{
printf("Usage: pracro -m MACRO -c CPR -U USER\n");
@@ -159,6 +164,11 @@ int main(int argc, char *argv[])
app.installTranslator(&translator);
}
+ QFontDatabase fontdb;
+ fontdb.addApplicationFont(":fonts/VeraMono.ttf");
+ QFont f = fontdb.font("Bitstream Vera Sans Mono", "", 8);
+ fixedfont = &f;
+
if(show_editor && show_viewer) {
MainWindow mainwindow(cpr, templ, host, port, user);
mainwindow.show();
diff --git a/client/resumewidget.cc b/client/resumewidget.cc
index ae6bec9..ac18578 100644
--- a/client/resumewidget.cc
+++ b/client/resumewidget.cc
@@ -32,10 +32,14 @@
#include <QTextEdit>
#include <QDialog>
+#include <QFont>
+
#define MAX_COMPACT_SIZE 100
//#define RICH // Experimental syntax highlighter (numbers turn blue)
-//#define FIXED_FONT // Show the resume, using a fixed font.
+#define FIXED_FONT // Show the resume, using a fixed font.
+
+extern QFont *fixedfont; // Defined in pracro.cc
ResumeWidget::ResumeWidget(bool compact)
{
@@ -79,24 +83,6 @@ static QString reformatString(QString help)
return output;
}
-#define LONGLINE 100
-static size_t countLongLines(QString str)
-{
- str += "\n"; // Make sure we end at a newline.
- size_t n = 0;
- size_t len = 0;
- for(size_t i = 0; i < (size_t)str.length(); i++) {
- if(str[i] != '\n') {
- len++;
- } else {
- n += len / LONGLINE;
- len = 0;
- }
- }
-
- return n;
-}
-
void ResumeWidget::setText(QString text)
{
QString f;
@@ -104,9 +90,7 @@ void ResumeWidget::setText(QString text)
fulltext = text;
#ifdef FIXED_FONT
- QFont font = resume->font();
- font.setFamily("Courier New");
- resume->setFont(font);
+ resume->setFont(*fixedfont);
#endif
#ifdef RICH
@@ -135,8 +119,7 @@ void ResumeWidget::setText(QString text)
//resume->setWhatsThis(fulltext); // Only set tooltip if resume has actually been cut off.
}
}
- size_t n = countLongLines(f);
- for(size_t i = 0; i < n; i++) f.append('\n');
+
resume->setText(f);
}
diff --git a/client/sessions.cc b/client/sessions.cc
new file mode 100644
index 0000000..d663b65
--- /dev/null
+++ b/client/sessions.cc
@@ -0,0 +1,119 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set et sw=2 ts=2: */
+/***************************************************************************
+ * sessions.cc
+ *
+ * Wed May 26 14:31:51 CEST 2010
+ * Copyright 2010 Bent Bisballe Nyeng
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of Pracro.
+ *
+ * Pracro 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 of the License, or
+ * (at your option) any later version.
+ *
+ * Pracro 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 Pracro; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#include "sessions.h"
+
+#include <QDialog>
+#include <QGridLayout>
+#include <QLabel>
+
+#define USER 0
+#define SESSIONID 1
+
+void Sessions::add(QString cpr, QString user, QString sessionid)
+{
+ QList<QVariant> data;
+ data.insert(USER, QVariant(user));
+ data.insert(SESSIONID, QVariant(sessionid));
+ s[cpr] = data;
+}
+
+void Sessions::remove(QString cpr)
+{
+ s.remove(cpr);
+}
+
+void Sessions::show()
+{
+ QDialog dlg;
+
+ QGridLayout *grid = new QGridLayout();
+ dlg.setLayout(grid);
+ dlg.setWindowTitle("Stored sessions");
+ dlg.setMinimumSize(300, 40);
+
+ QLabel *lcpr = new QLabel("CPR:");
+ QLabel *luser = new QLabel("User:");
+ QLabel *lid = new QLabel("SessionID:");
+
+ grid->addWidget(lcpr, 0, 0);
+ grid->addWidget(luser, 0, 1);
+ grid->addWidget(lid, 0, 2);
+
+ int row = 1;
+ QMap<QString, QVariant>::iterator i = s.begin();
+ while(i != s.end()) {
+ QString patientid = i.key();
+ QList<QVariant> data = i.value().toList();
+
+ QLabel *lcpr = new QLabel(patientid);
+ QLabel *luser = new QLabel(data[USER].toString());
+ QLabel *lid = new QLabel(data[SESSIONID].toString());
+
+ grid->addWidget(lcpr, row, 0);
+ grid->addWidget(luser, row, 1);
+ grid->addWidget(lid, row, 2);
+ row++;
+ i++;
+ }
+
+ dlg.exec();
+}
+
+bool Sessions::isEmpty()
+{
+ return s.size() == 0;
+}
+
+QVariant Sessions::toVariant()
+{
+ return s;
+}
+
+void Sessions::fromVariant(const QVariant &v)
+{
+ s = v.toMap();
+}
+
+bool Sessions::contains(QString cpr)
+{
+ return s.contains(cpr);
+}
+
+QString Sessions::getUser(QString cpr)
+{
+ if(!contains(cpr)) return "";
+ QList<QVariant> data = s[cpr].toList();
+ return data[USER].toString();
+}
+
+QString Sessions::getSessionID(QString cpr)
+{
+ if(!contains(cpr)) return "";
+ QList<QVariant> data = s[cpr].toList();
+ return data[SESSIONID].toString();
+}
diff --git a/client/sessions.h b/client/sessions.h
new file mode 100644
index 0000000..b42d27b
--- /dev/null
+++ b/client/sessions.h
@@ -0,0 +1,58 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set et sw=2 ts=2: */
+/***************************************************************************
+ * sessions.h
+ *
+ * Wed May 26 14:31:51 CEST 2010
+ * Copyright 2010 Bent Bisballe Nyeng
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of Pracro.
+ *
+ * Pracro 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 of the License, or
+ * (at your option) any later version.
+ *
+ * Pracro 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 Pracro; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#ifndef __PRACRO_SESSIONS_H__
+#define __PRACRO_SESSIONS_H__
+
+#include <QMap>
+#include <QString>
+#include <QVariant>
+
+//typedef QMap<QString, QList<QString> > Sessions;
+
+class Sessions {
+public:
+ void add(QString cpr, QString user, QString sessionid);
+ void remove(QString cpr);
+ void show();
+
+ QVariant toVariant();
+ void fromVariant(const QVariant &v);
+
+ bool contains(QString cpr);
+ QString getUser(QString cpr);
+ QString getSessionID(QString cpr);
+
+ bool isEmpty();
+
+private:
+ QMap<QString, QVariant > s;
+ // QMap<QString, QList<QString> > sessions;
+ //Sessions sessions;
+};
+
+#endif/*__PRACRO_SESSIONS_H__*/
diff --git a/client/viewer.cc b/client/viewer.cc
index 09b6e47..c4bd3f5 100644
--- a/client/viewer.cc
+++ b/client/viewer.cc
@@ -81,7 +81,12 @@ Viewer::Viewer(QString cpr, QString templs, QString host, quint16 port,
this->templs = templs.split(QRegExp("\\W+"), QString::SkipEmptyParts);
connect(&updatetimer, SIGNAL(timeout()), this, SLOT(update()));
- netcom = new NetCom(host, port, user, cpr);
+ netcom = new NetCom(host, port);
+ netcom->user = user;
+ netcom->patientid = cpr;
+ netcom->sessionid = "";
+ netcom->initConnection();
+
host = host; port = port; user = user;
this->cpr = cpr;
this->journalpath = journalpath;
@@ -109,6 +114,8 @@ Viewer::Viewer(QString cpr, QString templs, QString host, quint16 port,
Viewer::~Viewer()
{
+ updatetimer.stop();
+ netcom->discard(); // Make sure sessionid is removed.
delete netcom;
delete journal;
}
diff --git a/server/autogen.sh b/server/autogen.sh
index 45ef969..412286b 100755
--- a/server/autogen.sh
+++ b/server/autogen.sh
@@ -62,7 +62,7 @@ aclocalinclude="$ACLOCAL_FLAGS"; \
autoheader; \
echo "done.") && \
(echo $_echo_n " + Running automake: $_echo_c"; \
- automake --gnu --add-missing --copy; \
+ automake --gnu --add-missing --copy;\
echo "done.") && \
(echo $_echo_n " + Running autoconf: $_echo_c"; \
autoconf; \
diff --git a/server/configure.in b/server/configure.in
index b6beada..23a7172 100644
--- a/server/configure.in
+++ b/server/configure.in
@@ -1,7 +1,7 @@
# Filename: configure.in
AC_INIT(src/pracrod.cc)
-AM_INIT_AUTOMAKE( pracrod, 1.2.0 )
+AM_INIT_AUTOMAKE( pracrod, 1.1.0 )
dnl ======================
dnl Compile with debug options
@@ -17,15 +17,17 @@ if test x$with_debug == xyes; then
fi
dnl ======================
-dnl Compile without pentominos support
+dnl Compile with artefact support
dnl ======================
-AC_ARG_WITH(pentominos,
- [ --with-pentominos build with pentominos support (default=yes)],
+AC_ARG_WITH(artefact,
+ [ --with-artefact build with artefact support (default=yes)],
[],
- [with_pentominos=yes])
-if test x$with_pentominos == xno; then
- AC_MSG_WARN([*** Building without pentominos support!])
- AC_DEFINE_UNQUOTED(WITHOUT_PENTOMINOS, , [The project is configured not to use pentomimos])
+ [with_artefact=yes])
+if test x$with_artefact == xyes; then
+ PKG_CHECK_MODULES(ATF, libartefact >= 0.0.2)
+else
+ AC_MSG_WARN([*** Building without artefact support!])
+ AC_DEFINE_UNQUOTED(WITHOUT_ARTEFACT, , [The project is configured not to use artefact])
fi
dnl ======================
@@ -57,6 +59,23 @@ else
PKG_CHECK_MODULES(PQXX, libpqxx >= 2.6.8)
fi
+dnl ======================
+dnl Compile with ssl support?
+dnl ======================
+AC_ARG_WITH(ssl,
+ [ --with-ssl build with ssl support, requires microhttpd to be build with ssl support (default=yes)],
+ [],
+ [with_ssl=yes])
+if test x$with_ssl == xno; then
+ AC_MSG_WARN([*** Building without ssl support!])
+ AC_DEFINE_UNQUOTED(WITHOUT_SSL, , [The project is configured not to use ssl])
+else
+ AC_MSG_WARN([*** Building with ssl support!])
+ dnl ======================
+ dnl TODO: Check for ssl support in microhttpd
+ dnl ======================
+fi
+
AC_PROG_CXX
AC_PROG_LIBTOOL
@@ -126,20 +145,59 @@ dnl ======================
PKG_CHECK_MODULES(CONFIG, libconfig++ >= 1.0.1)
dnl ======================
-dnl Check for libartefact
+dnl Check for libmicrohttpd
dnl ======================
-PKG_CHECK_MODULES(ATF, libartefact >= 0.1.0)
+PKG_CHECK_MODULES(HTTPD, libmicrohttpd >= 0.4.4)
dnl ======================
dnl Check for eXpat library
dnl ======================
+tmp_CXXFLAGS="$CXXFLAGS"
+tmp_CPPFLAGS="$CPPFLAGS"
+tmp_CFLAGS="$CFLAGS"
+tmp_LDFLAGS="$LDFLAGS"
+tmp_LIBS="$LIBS"
+CXXFLAGS=""
+CPPFLAGS=""
+CFLAGS=""
+LDFLAGS=""
+LIBS=""
AC_CHECK_HEADER(expat.h, , AC_MSG_ERROR([*** eXpat header file not found!]))
-AC_CHECK_LIB(expat, XML_ParserCreate, , AC_MSG_ERROR([*** eXpat library not found!]))
-
-AC_SUBST(CFLAGS)
-AC_SUBST(CPPFLAGS)
-AC_SUBST(CXXFLAGS)
-AC_SUBST(LDFLAGS)
+AC_CHECK_LIB(expat, XML_ParserCreate, , AC_MSG_ERROR([*** eXpat library not found!]))
+EXPAT_CFLAGS="$CXXFLAGS $CPPFLAGS $CFLAGS"
+EXPAT_LIBS="$LDFLAGS $LIBS"
+CXXFLAGS="$tmp_CXXFLAGS"
+CPPFLAGS="$tmp_CPPFLAGS"
+CFLAGS="$tmp_CFLAGS"
+LDFLAGS="$tmp_LDFLAGS"
+LIBS="$tmp_LIBS"
+AC_SUBST(EXPAT_CFLAGS)
+AC_SUBST(EXPAT_LIBS)
+
+dnl ======================
+dnl Check for the pthread library
+dnl ======================
+tmp_CXXFLAGS="$CXXFLAGS"
+tmp_CPPFLAGS="$CPPFLAGS"
+tmp_CFLAGS="$CFLAGS"
+tmp_LDFLAGS="$LDFLAGS"
+tmp_LIBS="$LIBS"
+CXXFLAGS=""
+CPPFLAGS=""
+CFLAGS=""
+LDFLAGS=""
+LIBS=""
+AC_CHECK_HEADER(pthread.h, , AC_MSG_ERROR([*** pthread header file not found!]))
+AC_CHECK_LIB(pthread, pthread_mutex_init, , AC_MSG_ERROR([*** pthread library not found!]))
+PTHREAD_CFLAGS="$CXXFLAGS $CPPFLAGS $CFLAGS"
+PTHREAD_LIBS="$LDFLAGS $LIBS"
+CXXFLAGS="$tmp_CXXFLAGS"
+CPPFLAGS="$tmp_CPPFLAGS"
+CFLAGS="$tmp_CFLAGS"
+LDFLAGS="$tmp_LDFLAGS"
+LIBS="$tmp_LIBS"
+AC_SUBST(PTHREAD_CFLAGS)
+AC_SUBST(PTHREAD_LIBS)
AC_OUTPUT(
Makefile
diff --git a/server/etc/pracrod.conf b/server/etc/pracrod.conf
index 6d97619..5fb7494 100644
--- a/server/etc/pracrod.conf
+++ b/server/etc/pracrod.conf
@@ -2,3 +2,6 @@ port = 12345;
journal_commit_addr = "localhost";
journal_commit_port = 18112;
+
+artefact_addr = "localhost";
+artefact_port = 11108;
diff --git a/server/fieldnames.sql b/server/fieldnames.sql
index ecb21bc..9f52646 100644
--- a/server/fieldnames.sql
+++ b/server/fieldnames.sql
@@ -2,7 +2,7 @@
-- PostgreSQL database dump
--
-SET client_encoding = 'SQL_ASCII';
+SET client_encoding = 'UTF8';
SET standard_conforming_strings = off;
SET check_function_bodies = false;
SET client_min_messages = warning;
@@ -32,433 +32,113 @@ ALTER TABLE public.fieldnames OWNER TO pracro;
--
COPY fieldnames (name, description, "timestamp") FROM stdin;
-journal.resume Contains all macro generated journal resumes 1258638989
-90d_linse.mangler.odxt No description 1258711741
-90d_linse.indblik.odxt No description 1258711741
-90d_linse.implikation.odxt No description 1258711741
-90d_linse.randbloedninger.odxt No description 1258711741
-90d_linse.exsudaterater.odxt No description 1258711741
-retinal_haevelse_odxt No description 1258711741
-90d_linse.mangler.osin No description 1258711741
-90d_linse.indblik.osin No description 1258711741
-90d_linse.implikation.osin No description 1258711741
-90d_linse.randbloedninger.osin No description 1258711741
-90d_linse.exsudaterater.osin No description 1258711741
-retinal_haevelse_osin No description 1258711741
-90d_linse.yderligere No description 1258711741
-akselaengde.mangler.odxt No description 1258711741
-akselaengde.laengde.odxt No description 1258711741
-akselaengde.mangler.osin No description 1258711741
-akselaengde.laengde.osin No description 1258711741
-observeret_odxt No description 1258711741
-dato_odxt No description 1258711741
-aktuelle_entry_odxt No description 1258711741
-aktuelle.symptomer.odxt No description 1258711741
-observeret_osin No description 1258711741
-dato_osin No description 1258711741
-aktuelle_entry_osin No description 1258711741
-aktuelle.symptomer.osin No description 1258711741
-aktuelle.opstaaet No description 1258711741
-aktuelle.efterfoelgende No description 1258711741
-evolution No description 1258711741
-cave_multilist No description 1258711741
-cave No description 1258711741
-amd_behandling.begynd No description 1258711741
-amd.indikation.oeje No description 1258711741
-amd.indikation No description 1258711741
-amd.indikation.oeje No description 1258711741
-amd.indikation No description 1258711741
-amd_kontrolunders.begynd No description 1258711741
-lucentis_behandling.oeje No description 1258711741
-autorefraktion.mangler.odxt No description 1258711741
-autorefraktion.sf.odxt No description 1258711741
-autorefraktion.cyl.odxt No description 1258711741
-autorefraktion.grader.odxt No description 1258711741
-autorefraktion.mangler.osin No description 1258711741
-autorefraktion.sf.osin No description 1258711741
-autorefraktion.cyl.osin No description 1258711741
-autorefraktion.grader.osin No description 1258711741
-central_corneatykkelse.mangler.odxt No description 1258711741
-central_corneatykkelse.tykkelse.odxt No description 1258711741
-central_corneatykkelse.mangler.osin No description 1258711741
-central_corneatykkelse.tykkelse.osin No description 1258711741
-central_corneatykkelse.metode No description 1258711741
-cycloplegisk_refraktion.mangler.odxt No description 1258711741
-cycloplegisk_refraktion.sf.odxt No description 1258711741
-cycloplegisk_refraktion.cyl.odxt No description 1258711742
-cycloplegisk_refraktion.grader.odxt No description 1258711742
-cycloplegisk_refraktion.mangler.osin No description 1258711742
-cycloplegisk_refraktion.sf.osin No description 1258711742
-cycloplegisk_refraktion.cyl.osin No description 1258711742
-cycloplegisk_refraktion.grader.osin No description 1258711742
-de_5_trin.checkbox No description 1258711742
-brillemaaler.mangler.odxt No description 1258711742
-brillemaaler.sf.odxt No description 1258711742
-brillemaaler.cyl.odxt No description 1258711742
-brillemaaler.grader.odxt No description 1258711742
-brillemaaler.mangler.osin No description 1258711742
-brillemaaler.sf.osin No description 1258711742
-brillemaaler.cyl.osin No description 1258711742
-brillemaaler.grader.osin No description 1258711742
-fluorescens.oeje No description 1258711742
-fluorescens.tidlige_faser No description 1258711742
-fluorescens.angiografi_faser No description 1258711742
-fluorescens_injektion.oeje No description 1258711742
-fluorescens_injektion.initialer No description 1258711742
-fluorescens.konklusion.oeje No description 1258711742
-fluorescens.konklusion No description 1258711742
-fluorescens.membran.position No description 1258711742
-fluorescens.membran.stoerrelse No description 1258711742
-de_fem_trin No description 1258711742
-gravid_ammende No description 1258711742
-header.name No description 1258711742
-header.cpr No description 1258711742
-henvisning.laege No description 1258711742
-henvisning.diagnose_kode No description 1258711742
-henvisning.diagnose No description 1258711742
-henvisning.laege No description 1258711742
-henvisning.diagnose_kode No description 1258711742
-henvisning.diagnose No description 1258711742
-amd.information No description 1258711742
-amd.samtykke No description 1258711742
-amd.aftaler No description 1258711742
-intravitreal.initialer No description 1258711742
-keratometri.mangler.odxt No description 1258711742
-keratometri.r1.odxt No description 1258711742
-keratometri.r2.odxt No description 1258711742
-keratometri.x1.odxt No description 1258711742
-keratometri.mangler.osin No description 1258711742
-keratometri.r1.osin No description 1258711742
-keratometri.r2.osin No description 1258711742
-keratometri.x1.osin No description 1258711742
-manifest_refraktion.mangler.odxt No description 1258711742
-manifest_refraktion.sf.odxt No description 1258711742
-manifest_refraktion.cyl.odxt No description 1258711742
-manifest_refraktion.grader.odxt No description 1258711742
-manifest_refraktion.mangler.osin No description 1258711742
-manifest_refraktion.sf.osin No description 1258711742
-manifest_refraktion.cyl.osin No description 1258711742
-manifest_refraktion.grader.osin No description 1258711742
-medicin_list No description 1258711742
-medicin No description 1258711742
-oct.mangler.odxt No description 1258711742
-oct.tykkelse.odxt No description 1258711742
-oct.beskrivelse.odxt No description 1258711742
-oct.mangler.osin No description 1258711742
-oct.tykkelse.osin No description 1258711742
-oct.beskrivelse.osin No description 1258711742
-oct.kommentarer No description 1258711742
-oct.mangler.odxt No description 1258711742
-oct.tykkelse.odxt No description 1258711742
-oct.mangler.osin No description 1258711742
-oct.tykkelse.osin No description 1258711742
-oejendrypning.ocgtt.preparation No description 1258711742
-oejendrypning.ocgtt.initialer No description 1258711742
-oejendrypning.ocgtt.dato No description 1258711742
-tonometri.mangler.odxt No description 1258711742
-tonometri.tryk.odxt No description 1258711742
-tonometri.mangler.osin No description 1258711742
-tonometri.tryk.osin No description 1258711742
-tonometri.apparat No description 1258711742
-pupilstoerrelse.mangler.odxt No description 1258711742
-pupilstoerrelse.diameter.odxt No description 1258711742
-pupilstoerrelse.mangler.osin No description 1258711742
-pupilstoerrelse.diameter.osin No description 1258711742
-pupilstoerrelse.metode No description 1258711742
-spaltelampe.mangler.odxt No description 1258711742
-spaltelampe.konjuktiva.odxt No description 1258711742
-spaltelampe.epitel.intakt.odxt No description 1258711742
-spaltelampe.epitel.central_epiteldefekt.odxt No description 1258711742
-spaltelampe.epitel.toerhedsforandringer.odxt No description 1258711742
-spaltelampe.stroma.odxt No description 1258711742
-spaltelampe.flap.odxt No description 1258711742
-spaltelampe.folder.odxt No description 1258711742
-spaltelampe.interface.partikler.odxt No description 1258711742
-spaltelampe.interface.epitelindvaekst.odxt No description 1258711742
-spaltelampe.endothel.odxt No description 1258711742
-spaltelampe.lens.odxt No description 1258711742
-spaltelampe.supplerende.odxt No description 1258711742
-spaltelampe.mangler.osin No description 1258711743
-spaltelampe.konjuktiva.osin No description 1258711743
-spaltelampe.epitel.intakt.osin No description 1258711743
-spaltelampe.epitel.central_epiteldefekt.osin No description 1258711743
-spaltelampe.epitel.toerhedsforandringer.osin No description 1258711743
-spaltelampe.stroma.osin No description 1258711743
-spaltelampe.flap.osin No description 1258711743
-spaltelampe.folder.osin No description 1258711743
-spaltelampe.partikler.osin No description 1258711743
-spaltelampe.epitelindvaekst.osin No description 1258711743
-spaltelampe.endothel.osin No description 1258711743
-spaltelampe.lens.osin No description 1258711743
-spaltelampe.supplerende.osin No description 1258711743
-90d_linse.mangler.odxt No description 1258711743
-90d_linse.indblik.odxt No description 1258711743
-90d_linse.papil.odxt No description 1258711743
-90d_linse.makula.odxt No description 1258711743
-90d_linse.periferi.odxt No description 1258711743
-90d_linse.hul_eller_rift_kl.odxt No description 1258711743
-90d_linse.supplerende.odxt No description 1258711743
-90d_linse.mangler.osin No description 1258711743
-90d_linse.indblik.osin No description 1258711743
-90d_linse.papil.osin No description 1258711743
-90d_linse.makula.osin No description 1258711743
-90d_linse.periferi.osin No description 1258711743
-90d_linse.hul_eller_rift_kl.osin No description 1258711743
-90d_linse.supplerende.osin No description 1258711743
-ref_aktuelle.bruger_nu No description 1258711743
-ref_aktuelle.stabilitet No description 1258711743
-ref_aktuelle.yderligere_kommentarer No description 1258711743
-ref_aktuelle.forventninger No description 1258711743
-ref_behandling.kirurgisk_procedure.type No description 1258711743
-ref_behandling.kirurgisk_procedure.oeje No description 1258711743
-ref_behandling.kirurgisk_procedure.lasik.metode No description 1258711743
-ref_behandling.kirurgisk_procedure.lasik.flapdiameter No description 1258711743
-ref_behandling.kirurgisk_procedure.lasik.flaptykkelse No description 1258711743
-ref_behandling.kirurgisk_procedure.lasik.kantprofil No description 1258711743
-ref_behandling.kirurgisk_procedure.prk.part1 No description 1258711743
-ref_behandling.kirurgisk_procedure.relasik.part1 No description 1258711743
-ref_behandling.kirurgisk_procedure.lasek.part1 No description 1258711743
-ref_behandling.kirurgisk_procedure.fotoablation.algoritme No description 1258711743
-ref_behandling.kirurgisk_procedure.fotoablation.sf No description 1258711743
-ref_behandling.kirurgisk_procedure.fotoablation.cyl No description 1258711743
-ref_behandling.kirurgisk_procedure.fotoablation.grader No description 1258711743
-ref_behandling.kirurgisk_procedure.fotoablation.ablationsdiameter No description 1258711743
-ref_behandling.kirurgisk_procedure.fotoablation.ablationsdybde No description 1258711743
-ref_behandling.kirurgisk_procedure.lasik.part2 No description 1258711743
-ref_behandling.kirurgisk_procedure.prk.part2 No description 1258711743
-ref_behandling.kirurgisk_procedure.relasik.part2 No description 1258711743
-ref_behandling.kirurgisk_procedure.lasek.part2 No description 1258711743
-ref_behandling.kirurgisk_procedure.drypperegime No description 1258711743
-ref_behandling.kirurgisk_procedure.komplikationer No description 1258711743
-ref_behandling.klargoering.initialer No description 1258711743
-ref_efterkontrol.aktuelle.afstandssyn No description 1258711743
-ref_efterkontrol.aktuelle.nattesyn No description 1258711743
-ref_efterkontrol.aktuelle.oejengener No description 1258711743
-ref_efterkontrol.aktuelle.tilfredshed No description 1258711743
-ref_efterkontrol.aktuelle.yderligere_kommentarer No description 1258711743
-ref_efterkontrol.informeret_samtykke.informeret_samtykke No description 1258711743
-ref_efterkontrol.informeret_samtykke.yderligere_kommentarer No description 1258711743
-ref_efterkontrol.konklusion.konklusion No description 1258711743
-ref_efterkontrol.konklusion.rebehandling No description 1258711743
-ref_efterkontrol.konklusion.oeje No description 1258711743
-ref_efterkontrol.konklusion.yderligere_kommentarer No description 1258711743
-ref_efterkontrol.overskrift.type No description 1258711743
-ref_efterkontrol.overskrift.maaneder No description 1258711743
-ref_foerstedagskontrol.overskrift.type No description 1258711743
-ref_forunders.informeret_samtykke.informeret_samtykke No description 1258711743
-ref_forunders.informeret_samtykke.yderligere_kommentarer No description 1258711743
-ref_forunders.konklusion.konklusion No description 1258711743
-ref_forunders.konklusion.behandling No description 1258711743
-ref_forunders.konklusion.oeje No description 1258711743
-ref_forunders.konklusion.maal No description 1258711743
-ref_forunders.konklusion.yderligere_kommentarer No description 1258711743
-ref.komplikationer No description 1258711743
-ref.kontrol No description 1258711743
-ref.oejendrypning.drypperegime No description 1258711743
-ref.oejendrypning.ordinering No description 1258711743
-ref.oejendrypning.mod_smerter No description 1258711743
-ref.subjektivt.smerter No description 1258711743
-ref.subjektivt.syn No description 1258711743
-spaltelampe.mangler.odxt No description 1258711743
-spaltelampe.observation.odxt No description 1258711743
-spaltelampe.yderligere.odxt No description 1258711743
-spaltelampe.mangler.osin No description 1258711743
-spaltelampe.observation.osin No description 1258711743
-spaltelampe.yderligere.osin No description 1258711743
-spaltelampe.mangler.odxt No description 1258711743
-spaltelampe.konjuktiva.odxt No description 1258711743
-spaltelampe.epitel.intakt.odxt No description 1258711743
-spaltelampe.epitel.central_epiteldefekt.odxt No description 1258711743
-spaltelampe.epitel.toerhedsforandringer.odxt No description 1258711743
-spaltelampe.stroma.odxt No description 1258711743
-spaltelampe.flap.odxt No description 1258711744
-spaltelampe.folder.odxt No description 1258711744
-spaltelampe.interface.partikler.odxt No description 1258711744
-spaltelampe.interface.epitelindvaekst.odxt No description 1258711744
-spaltelampe.endothel.odxt No description 1258711744
-spaltelampe.lens.odxt No description 1258711744
-spaltelampe.supplerende.odxt No description 1258711744
-spaltelampe.mangler.osin No description 1258711744
-spaltelampe.konjuktiva.osin No description 1258711744
-spaltelampe.epitel.intakt.osin No description 1258711744
-spaltelampe.epitel.central_epiteldefekt.osin No description 1258711744
-spaltelampe.epitel.toerhedsforandringer.osin No description 1258711744
-spaltelampe.stroma.osin No description 1258711744
-spaltelampe.flap.osin No description 1258711744
-spaltelampe.folder.osin No description 1258711744
-spaltelampe.partikler.osin No description 1258711744
-spaltelampe.epitelindvaekst.osin No description 1258711744
-spaltelampe.endothel.osin No description 1258711744
-spaltelampe.lens.osin No description 1258711744
-spaltelampe.supplerende.osin No description 1258711744
-amd.subjektiv_evaluering No description 1258711744
-supplerende No description 1258711744
-detaljer No description 1258711744
-tidligere_almene_sygdomme No description 1258711744
-detaljer No description 1258711744
-tidligere_oejensygdomme No description 1258711744
-missing_eye_odxt No description 1258711744
-missing_eye_osin No description 1258711744
-tobak.forbrug No description 1258711744
-tonometri.mangler.odxt No description 1258711744
-tonometri.tryk.odxt No description 1258711744
-tonometri.mangler.osin No description 1258711744
-tonometri.tryk.osin No description 1258711744
-tonometri.metode No description 1258711744
-topografi.metode No description 1258711744
-topografi.mangler.odxt No description 1258711744
-topografi.bedoemmelse.odxt No description 1258711744
-topografi.mangler.osin No description 1258711744
-topografi.bedoemmelse.osin No description 1258711744
-snellen.mangler.odxt No description 1258711744
-snellen.odxt No description 1258711744
-etdrs.odxt No description 1258711744
-snellen.korr.basis.odxt No description 1258711744
-snellen.korr.sf.odxt No description 1258711744
-snellen.korr.cyl.odxt No description 1258711744
-snellen.korr.grader.odxt No description 1258711744
-snellen.mangler.osin No description 1258711744
-snellen.osin No description 1258711744
-etdrs.osin No description 1258711744
-snellen.korr.basis.osin No description 1258711744
-snellen.korr.sf.osin No description 1258711744
-snellen.korr.cyl.osin No description 1258711744
-snellen.korr.grader.osin No description 1258711744
-visus.autoref.mangler.odxt No description 1258711744
-visus.autoref.kontrast.odxt No description 1258711744
-visus.autoref.st_hul.odxt No description 1258711744
-visus.autoref.snellen.odxt No description 1258711744
-visus.autoref.etdrs.odxt No description 1258711744
-visus.autoref.korr.sf.odxt No description 1258711744
-visus.autoref.korr.cyl.odxt No description 1258711744
-visus.autoref.korr.grader.odxt No description 1258711744
-visus.autoref.mangler.osin No description 1258711744
-visus.autoref.kontrast.osin No description 1258711744
-visus.autoref.st_hul.osin No description 1258711744
-visus.autoref.snellen.osin No description 1258711744
-visus.autoref.etdrs.osin No description 1258711744
-visus.autoref.korr.sf.osin No description 1258711744
-visus.autoref.korr.cyl.osin No description 1258711744
-visus.autoref.korr.grader.osin No description 1258711744
-visus.egen_korr.mangler.odxt No description 1258711744
-visus.egen_korr.kontrast.odxt No description 1258711744
-visus.egen_korr.snellen.odxt No description 1258711744
-visus.egen_korr.etdrs.odxt No description 1258711744
-visus.egen_korr.korr.sf.odxt No description 1258711744
-visus.egen_korr.korr.cyl.odxt No description 1258711744
-visus.egen_korr.korr.grader.odxt No description 1258711744
-visus.egen_korr.st_hul.odxt No description 1258711744
-visus.egen_korr.st_hul.snellen.odxt No description 1258711744
-visus.egen_korr.st_hul.etdrs.odxt No description 1258711744
-visus.egen_korr.mangler.osin No description 1258711744
-visus.egen_korr.kontrast.osin No description 1258711744
-visus.egen_korr.snellen.osin No description 1258711744
-visus.egen_korr.etdrs.osin No description 1258711744
-visus.egen_korr.korr.sf.osin No description 1258711744
-visus.egen_korr.korr.cyl.osin No description 1258711744
-visus.egen_korr.korr.grader.osin No description 1258711744
-visus.egen_korr.st_hul.osin No description 1258711744
-visus.egen_korr.st_hul.snellen.osin No description 1258711744
-visus.egen_korr.st_hul.etdrs.osin No description 1258711744
-visus.egen_korr.ou No description 1258711744
-visus.egen_korr.kontrast.ou No description 1258711744
-visus.egen_korr.snellen.ou No description 1258711744
-visus.egen_korr.etdrs.ou No description 1258711744
-visus.manifest_refraktion.mangler.odxt No description 1258711745
-visus.manifest_refraktion.kontrast.odxt No description 1258711745
-visus.manifest_refraktion.snellen.odxt No description 1258711745
-visus.manifest_refraktion.etdrs.odxt No description 1258711745
-visus.manifest_refraktion.korr.sf.odxt No description 1258711745
-visus.manifest_refraktion.korr.cyl.odxt No description 1258711745
-visus.manifest_refraktion.korr.grader.odxt No description 1258711745
-visus.manifest_refraktion.st_hul.odxt No description 1258711745
-visus.manifest_refraktion.st_hul.snellen.odxt No description 1258711745
-visus.manifest_refraktion.st_hul.etdrs.odxt No description 1258711745
-visus.manifest_refraktion.mangler.osin No description 1258711745
-visus.manifest_refraktion.kontrast.osin No description 1258711745
-visus.manifest_refraktion.snellen.osin No description 1258711745
-visus.manifest_refraktion.etdrs.osin No description 1258711745
-visus.manifest_refraktion.korr.sf.osin No description 1258711745
-visus.manifest_refraktion.korr.cyl.osin No description 1258711745
-visus.manifest_refraktion.korr.grader.osin No description 1258711745
-visus.manifest_refraktion.st_hul.osin No description 1258711745
-visus.manifest_refraktion.st_hul.snellen.osin No description 1258711745
-visus.manifest_refraktion.st_hul.etdrs.osin No description 1258711745
-visus.manifest_refraktion.ou No description 1258711745
-visus.manifest_refraktion.kontrast.ou No description 1258711745
-visus.manifest_refraktion.snellen.ou No description 1258711745
-visus.manifest_refraktion.etdrs.ou No description 1258711745
-visus.ou.kontrast No description 1258711745
-visus.ou.st_hul No description 1258711745
-visus.ou.snellen No description 1258711745
-visus.ou.etdrs No description 1258711745
-visus.ou.korr.sf No description 1258711745
-visus.ou.korr.cyl No description 1258711745
-visus.ou.korr.grader No description 1258711745
-visus.template.mangler.odxt No description 1258711745
-visus.template.kontrast.odxt No description 1258711745
-visus.template.snellen.odxt No description 1258711745
-visus.template.etdrs.odxt No description 1258711745
-visus.template.korr.sf.odxt No description 1258711745
-visus.template.korr.cyl.odxt No description 1258711745
-visus.template.korr.grader.odxt No description 1258711745
-visus.template.add.sf.odxt No description 1258711745
-visus.template.add.cyl.odxt No description 1258711745
-visus.template.add.grader.odxt No description 1258711745
-visus.template.st_hul.odxt No description 1258711745
-visus.template.st_hul.snellen.odxt No description 1258711745
-visus.template.st_hul.etdrs.odxt No description 1258711745
-visus.template.mangler.osin No description 1258711745
-visus.template.kontrast.osin No description 1258711745
-visus.template.snellen.osin No description 1258711745
-visus.template.etdrs.osin No description 1258711745
-visus.template.korr.sf.osin No description 1258711745
-visus.template.korr.cyl.osin No description 1258711745
-visus.template.korr.grader.osin No description 1258711745
-visus.template.add.sf.osin No description 1258711745
-visus.template.add.cyl.osin No description 1258711745
-visus.template.add.grader.osin No description 1258711745
-visus.template.st_hul.osin No description 1258711745
-visus.template.st_hul.snellen.osin No description 1258711745
-visus.template.st_hul.etdrs.osin No description 1258711745
-visus.template.ou No description 1258711745
-visus.template.kontrast.ou No description 1258711745
-visus.template.snellen.ou No description 1258711745
-visus.template.etdrs.ou No description 1258711745
-visus.uden_korr.mangler.odxt No description 1258711745
-visus.uden_korr.kontrast.odxt No description 1258711745
-visus.uden_korr.snellen.odxt No description 1258711745
-visus.uden_korr.etdrs.odxt No description 1258711745
-visus.uden_korr.st_hul.odxt No description 1258711745
-visus.uden_korr.st_hul.snellen.odxt No description 1258711745
-visus.uden_korr.st_hul.etdrs.odxt No description 1258711745
-visus.uden_korr.mangler.osin No description 1258711745
-visus.uden_korr.kontrast.osin No description 1258711745
-visus.uden_korr.snellen.osin No description 1258711745
-visus.uden_korr.etdrs.osin No description 1258711745
-visus.uden_korr.st_hul.osin No description 1258711745
-visus.uden_korr.st_hul.snellen.osin No description 1258711745
-visus.uden_korr.st_hul.etdrs.osin No description 1258711745
-visus.uden_korr.ou No description 1258711745
-visus.uden_korr.kontrast.ou No description 1258711745
-visus.uden_korr.snellen.ou No description 1258711745
-visus.uden_korr.etdrs.ou No description 1258711745
-fundus.kilde No description 1258711745
-fundus.randhaemorrhagier No description 1258711745
-fundus.exsudater No description 1258711745
-amd_preop.konklusion.oeje No description 1258711745
-amd_preop.konklusion No description 1258711745
-amd_preop.konklusion.yderligere No description 1258711745
-amd_preop.konklusion.afsluttes No description 1258711745
-boelgefront.odxt No description 1260355433
-boelgefront.osin No description 1260355438
-boelgefront.aberration.odxt No description 1260355451
-boelgefront.aberration.osin No description 1260355454
-boelgefront.pupilstoerrelse.odxt No description 1260355463
-boelgefront.pupilstoerrelse.osin No description 1260355467
-boelgefront.mangler.odxt No description 1260355482
-boelgefront.mangler.osin No description 1260355487
-90d_linse.hul_eller_rift_kl.odxt No description 1265799742
+cave Listen over medicintyper og reaktioner som en patient er overfølsom overfor. 0
+medicin Liste over medicin som patienten i forvejen modtager (og som har relevans for undersøgelsen). 0
+previous_common_diseases Liste over tidligere almene sygdomme. 0
+amd.consent Har patienten givet sit samtykke til AMD behandling? 0
+amd.indication Indikation for AMD. 0
+amd.information Har patienten modtaget en informationsfolder om AMD forløbet? 0
+tobacco Information om patientens rygevaner. 0
+previous_eye_diseases Tidligere øjensygdomme som har relevans for aktuelle. 0
+snellen.left Snellen tavle værdi for venstre øje. 0
+snellen.right Snellen tavle værdi for højre øje. 0
+etdrs.left ETDRS værdi for venstre øje. 0
+etdrs.right ETDRS værdi for højre øje. 0
+lensmeter.left.sphere Lensmeter sphere på venstre brille. 0
+lensmeter.left.cyl Lensmeter cylinder på venstre brille. 0
+lensmeter.left.axis Lensmeter akse på venstre brille. 0
+lensmeter.right.sphere Lensmeter sphere på højre brille. 0
+lensmeter.right.cyl Lensmeter cylinder på højre brille. 0
+lensmeter.right.axis Lensmeter akse på højre brille. 0
+autorefractor.left.sphere Autorefraktor sphere på venstre øje. 0
+autorefractor.left.cyl Autorefraktor cylinder på venstre øje. 0
+autorefractor.left.axis Autorefraktor akse på venstre øje. 0
+autorefractor.right.sphere Autorefraktor sphere på højre øje. 0
+autorefractor.right.cyl Autorefraktor cylinder på højre øje. 0
+autorefractor.right.axis Autorefraktor akse på højre øje. 0
+tonometer.pressure.left Tonometer trykmål på venstre øje. 0
+tonometer.pressure.right Tonometer trykmål på højre øje. 0
+tonometer.device Tonometer apparatur benyttet til målingen. 0
+oct.left.thickness OCT tykkelse på venstre øje. 0
+oct.left.description OCT beskrivelse på vrnstre øje. 0
+oct.right.thickness OCT tykkelse på højre øje. 0
+oct.comments OCT kommentarer. 0
+oct.right.description OCT beskrivelse på højre øje. 0
+slit_lamp.left.observation Spaltelampe observation, venstre øje. 0
+slit_lamp.left.additional Spaltelampe supplerende information, venstre øje. 0
+slit_lamp.right.observation Spaltelampe observation, højre øje. 0
+slit_lamp.right.additional Spaltelampe supplerende information, højre øje. 0
+90D_lens.implications 90D linse implikationsliste. 0
+90D_lens.right.fundus_visibility Indblik til fundusbaggrunden, højre øje. 0
+90D_lens.left.fundus_visibility Indblik til fundusbaggrunden, venstre øje. 0
+amd_preop.conclusion_terminated AMD forundersøgelse, afsluttes. 0
+amd_preop.conclusion_additional AMD forundersøgelse, bemærkninger. 0
+amd_preop.conclusion AMD forundersøgelse, konklusion. 0
+fluorescens.early_fases Fluorescens tidlige faser. 0
+fluorescens.angiografic_fases Fluorescens angiografiske faser. 0
+ocgtt.preparation Det/de ogctt præparat der er dryppet med. 0
+ocgtt.initials Initialer på den person som har foretaget ocgtt drypning. 0
+fluorescens.conclusion Konklusion på fluoresces undersøgelsen. 0
+fluorescens.additional_info Yderligere information til fluorescens konklusion (membran størrelse og placering) 0
+ocgtt.date Tidspunkt for drypning i unixtime (UTC). 0
+missing_eye_left Indikerer at der ikke kan måles på det venstre øje. 0
+missing_eye_right Indikerer at der ikke kan måles på det højre øje. 0
+test1 \N \N
+test2 \N \N
+snellen.left.missing Den venstre snellen måling er ikke foretaget. 0
+snellen.right.missing Den højre snellen måling er ikke foretaget. 0
+lensmeter.left.missing Den venstre lensmeter måling er ikke foretaget. 0
+lensmeter.right.missing Den højre lensmeter måling er ikke foretaget. 0
+journal.resume Journal resume text 1234274034
+fluorescein_injection.eye Indikation af hvilket øje der injiceres. 0
+fluorescein_injection.initials Initialer på den person som har injiceret fluorescein. 0
+fluorescens.eye Indikation af hvilket øje der beskrives. 0
+fluorescens.conclusion.eye Indikation af hvilket øje der konkluderes på. 0
+amd.indication.eye Indikation af hvilket øje der stilles behandlings indikation på. 0
+amd.agreements Felt til yderligere aftaler med patienten 0
+slit_lamp.right.missing Manglende højre øje, ved spaltelampeundersøgelse. 0
+slit_lamp.left.missing Manglende venstre øje, ved spaltelampeundersøgelse. 0
+tonometer.right.missing Manglende højre øje, ved tonometerundersøgelse. 0
+fluorescens.conclusion.other Fluorescens membran kommentar. 0
+tonometer.left.missing Manglende venstre øje, ved tonometerundersøgelse. 0
+oct.left.missing Manglende venstre øje, ved OCT undersøgelse. 0
+autorefractor.left.missing Manglende venstre øje, ved autorefractor undersøgelse. 0
+oct.right.missing Manglende højre øje, ved OCT undersøgelse. 0
+autorefractor.right.missing Manglende højre øje, ved autorefractor undersøgelse. 0
+fluorescens.membrane.size Fluorescens membran størrelse. 0
+fluorescens.membrane.position Fluorescens membran position. 0
+current.when Aktuelle opstået 0
+current.then Aktuelle udvikling 0
+intravitreal.initials Initialier på den person som ar udført intravitreal injicering. 0
+lucentis_treatment.eye Lucentis behandlig af hvilket øje? 0
+five_steps Gennemgang af de 5 trin. 0
+current.symptoms.right Aktuelle symptomer (liste) på højre øje. 0
+current.symptoms.left Aktuelle symptomer (liste) på venstre øje. 0
+amd.subjective_evaluation Subjektiv evaluering siden sidst. 0
+fundus.source Kilde for fundus evaluering 0
+fundus.randh Findes der Randhæmorrhagier 0
+fundus.exsud Findes der Exsudater 0
+90D_lens.right.implikation Hvad observeres på højre øje? 0
+90D_lens.left.implikation Hvad observeres på venstre øje? 0
+90D_lens.right.randbl Er der randblødning på højre øje? 0
+90D_lens.left.randbl Er der randblødning på venstre øje? 0
+90D_lens.right.exsudater Er der exhudater på højre øje? 0
+90D_lens.left.exsudater Er der exhudater på venstre øje? 0
+90D_lens.additional Supplerende oplysninger om 90D linse undersøgelsen 0
+90D_lens.left.missing Manglende venstre øje, ved 90D linse undersøglesen \N
+90D_lens.right.missing Manglende højre øje, ved 90D linse undersøglesen \N
+snellen.right.corr.cyl \N \N
+snellen.right.corr.sph \N \N
+snellen.right.corr.basis \N \N
+snellen.left.corr.cyl \N \N
+snellen.left.corr.sph \N \N
+snellen.left.corr.basis \N \N
+snellen.right.corr.axis \N \N
+snellen.left.corr.axis \N \N
+referral.doctor \N \N
+referral.diagnose \N \N
+referral.diagnosecode \N \N
+amd_preop.conclusion.eye AMD preop konklusinens øje 0
\.
diff --git a/server/src/.cvsignore b/server/src/.cvsignore
index e7654ee..6fa7094 100644
--- a/server/src/.cvsignore
+++ b/server/src/.cvsignore
@@ -4,4 +4,5 @@ Makefile.in
Makefile
.libs
.deps
-test_* \ No newline at end of file
+test_*
+tests.make \ No newline at end of file
diff --git a/server/src/Makefile.am b/server/src/Makefile.am
index 98a154e..942ced5 100644
--- a/server/src/Makefile.am
+++ b/server/src/Makefile.am
@@ -2,25 +2,33 @@
bin_PROGRAMS = pracrod macrotool
pracrod_LDADD = $(LD_EFENCE) $(PQXX_LIBS) $(CONFIG_LIBS) \
- $(LUA_LIBS) $(HTTPD_LIBS) -lpthread $(ATF_LIBS)
+ $(LUA_LIBS) $(HTTPD_LIBS) $(PTHREAD_LIBS) \
+ $(EXPAT_LIBS) $(ATF_LIBS)
pracrod_CXXFLAGS = $(PQXX_CXXFLAGS) $(CONFIG_CXXFLAGS) \
- $(LUA_CXXFLAGS) $(HTTPD_CFLAGS) $(ATF_CFLAGS)
+ $(LUA_CXXFLAGS) $(HTTPD_CFLAGS) $(EXPAT_CFLAGS) \
+ $(PTHREAD_CFLAGS) $(ATF_CFLAGS)
pracrod_SOURCES = \
pracrod.cc \
+ artefact.cc \
daemon.cc \
database.cc \
configuration.cc \
configurationparser.cc \
+ connection.cc \
+ connectionpool.cc \
debug.cc \
+ entitylist.cc \
+ environment.cc \
exception.cc \
- queryhandlerpentominos.cc \
- queryhandlerpracro.cc \
+ inotify.cc \
journal_commit.cc \
+ journalwriter.cc \
log.cc \
luaquerymapper.cc \
luaresume.cc \
+ luautil.cc \
macroheaderparser.cc \
macrolist.cc \
macroparser.cc \
@@ -28,12 +36,20 @@ pracrod_SOURCES = \
pracrodao.cc \
pracrodaopgsql.cc \
pracrodaotest.cc \
+ queryhandlerpentominos.cc \
+ queryhandlerpracro.cc \
+ queryparser.cc \
resumeparser.cc \
saxparser.cc \
+ semaphore.cc \
server.cc \
+ session.cc \
+ sessionparser.cc \
+ sessionserialiser.cc \
templatelist.cc \
templateheaderparser.cc \
templateparser.cc \
+ transactionhandler.cc \
transactionparser.cc \
tcpsocket.cc \
utf8.cc \
@@ -41,9 +57,11 @@ pracrod_SOURCES = \
widgetgenerator.cc \
xml_encode_decode.cc
-macrotool_LDADD = $(LD_EFENCE) $(PQXX_LIBS) $(CONFIG_LIBS) $(LUA_LIBS) -lpthread
+macrotool_LDADD = $(LD_EFENCE) $(PQXX_LIBS) $(CONFIG_LIBS) \
+ $(LUA_LIBS) $(PTHREAD_LIBS) $(EXPAT_LIBS)
-macrotool_CXXFLAGS = $(PQXX_CXXFLAGS) $(CONFIG_CXXFLAGS) $(LUA_CXXFLAGS)
+macrotool_CXXFLAGS = $(PQXX_CXXFLAGS) $(CONFIG_CXXFLAGS) \
+ $(LUA_CXXFLAGS) $(PTHREAD_CFLAGS) $(EXPAT_CFLAGS)
macrotool_SOURCES = \
macrotool.cc \
@@ -51,7 +69,9 @@ macrotool_SOURCES = \
configuration.cc \
configurationparser.cc \
database.cc \
+ entitylist.cc \
exception.cc \
+ inotify.cc \
log.cc \
macroheaderparser.cc \
macrolist.cc \
@@ -69,20 +89,25 @@ macrotool_SOURCES = \
versionstr.cc
EXTRA_DIST = \
+ artefact.h \
configuration.h \
configurationparser.h \
+ connection.h \
+ connectionpool.h \
daemon.h \
database.h \
dbtypes.h \
debug.h \
+ environment.h \
+ entitylist.h \
exception.h \
- queryhandler.h \
- queryhandlerpentominos.h \
- queryhandlerpracro.h \
+ inotify.h \
journal_commit.h \
+ journalwriter.h \
log.h \
luaquerymapper.h \
luaresume.h \
+ luautil.h \
macroheaderparser.h \
macrolist.h \
macroparser.h \
@@ -94,15 +119,21 @@ EXTRA_DIST = \
pracrodao.h \
pracrodaopgsql.h \
pracrodaotest.h \
- queryresult.h \
+ queryhandler.h \
+ queryhandlerpentominos.h \
+ queryhandlerpracro.h \
+ queryparser.h \
resumeparser.h \
saxparser.h \
+ semaphore.h \
server.h \
- template.h \
+ session.h \
+ sessionparser.h \
+ sessionserialiser.h \
templatelist.h \
templateheaderparser.h \
templateparser.h \
- transaction.h \
+ transactionhandler.h \
transactionparser.h \
tcpsocket.h \
utf8.h \
@@ -114,217 +145,10 @@ EXTRA_DIST = \
# Test Section #
################
-TESTFILES = \
- test_tcpsocket \
- test_pracrodaotest \
- test_widgetgenerator \
- test_configurationparser \
- test_exception \
- test_templateheaderparser \
- test_macroheaderparser \
- test_templatelist \
- test_saxparser \
- test_transactionparser \
- test_versionstr \
- test_macrolist \
- test_queryhandlerpentominos \
- test_queryhandlerpracro \
- test_luaquerymapper \
- test_templateparser \
- test_server \
- test_pracrodaopgsql \
- test_macroparser \
- test_xml_encode_decode \
- test_journal_commit
-
-TESTLOGS = `for F in ${TESTFILES}; do echo $$F.log; done`
-
-BASICFILES = exception.cc log.cc debug.cc configuration.cc utf8.cc
-BASICFLAGS = -I.. -DHAVE_CONFIG_H $(CONFIG_CXXFLAGS) $(CONFIG_LIBS)
-
-PARSERFILES = saxparser.cc
-PARSERFLAGS = -lexpat
-
-DBFILES = database.cc pracrodao.cc pracrodaopgsql.cc pracrodaotest.cc mutex.cc
-DBFLAGS = $(PQXX_LIBS) $(PQXX_CXXFLAGS)
-
-test: $(TESTFILES)
- @echo "All tests done."
-
-test_clean:
- rm -f $(TESTFILES) $(TESTLOGS)
-
-TEST_TCPSOCKET_FILES = \
- tcpsocket.cc \
- $(BASICFILES)
-test_tcpsocket: $(TEST_TCPSOCKET_FILES)
- @../../tools/test $(TEST_TCPSOCKET_FILES) $(BASICFLAGS)
-
-TEST_PRACRODAOTEST_FILES = \
- pracrodaotest.cc \
- pracrodao.cc \
- $(BASICFILES)
-test_pracrodaotest: $(TEST_PRACRODAOTEST_FILES)
- @../../tools/test $(TEST_PRACRODAOTEST_FILES) $(BASICFLAGS)
-
-TEST_WIDGETGENERATOR_FILES = \
- widgetgenerator.cc \
- xml_encode_decode.cc \
- luaquerymapper.cc \
- $(BASICFILES) \
- $(DBFILES)
-test_widgetgenerator: $(TEST_WIDGETGENERATOR_FILES)
- @../../tools/test $(TEST_WIDGETGENERATOR_FILES) $(BASICFLAGS) $(LUA_LIBS) $(DBFLAGS)
-
-TEST_CONFIGURATIONPARSER_FILES = \
- configurationparser.cc \
- configuration.cc \
- exception.cc \
- log.cc
-test_configurationparser: $(TEST_CONFIGURATIONPARSER_FILES)
- @../../tools/test $(TEST_CONFIGURATIONPARSER_FILES) $(BASICFLAGS)
-
-TEST_EXCEPTION_FILES = \
- exception.cc \
- log.cc
-test_exception: $(TEST_EXCEPTION_FILES)
- @../../tools/test $(TEST_EXCEPTION_FILES)
-
-TEST_TEMPLATEHEADERPARSER_FILES = \
- templateheaderparser.cc \
- $(PARSERFILES) \
- $(BASICFILES)
-test_templateheaderparser: $(TEST_TEMPLATEHEADERPARSER_FILES)
- @../../tools/test $(TEST_TEMPLATEHEADERPARSER_FILES) $(BASICFLAGS) $(PARSERFLAGS)
-
-TEST_MACROHEADERPARSER_FILES = \
- macroheaderparser.cc \
- $(PARSERFILES) \
- $(BASICFILES)
-test_macroheaderparser: $(TEST_MACROHEADERPARSER_FILES)
- @../../tools/test $(TEST_MACROHEADERPARSER_FILES) $(BASICFLAGS) $(PARSERFLAGS)
-
-TEST_TEMPLATELIST_FILES = \
- templatelist.cc \
- versionstr.cc \
- templateheaderparser.cc \
- $(PARSERFILES) \
- $(BASICFILES)
-test_templatelist: $(TEST_TEMPLATELIST_FILES)
- @../../tools/test $(TEST_TEMPLATELIST_FILES) $(PARSERFLAGS) $(BASICFLAGS)
-
-TEST_MACROLIST_FILES = \
- macrolist.cc \
- versionstr.cc \
- macroheaderparser.cc \
- $(PARSERFILES) \
- $(BASICFILES)
-test_macrolist: $(TEST_MACROLIST_FILES)
- @../../tools/test $(TEST_MACROLIST_FILES) $(PARSERFLAGS) $(BASICFLAGS)
-
-TEST_SAXPARSER_FILES = \
- saxparser.cc \
- $(BASICFILES)
-test_saxparser: $(TEST_SAXPARSER_FILES)
- @../../tools/test $(TEST_SAXPARSER_FILES) $(BASICFLAGS) $(PARSERFLAGS)
-
-TEST_TRANSACTIONPARSER_FILES = \
- transactionparser.cc \
- $(BASICFILES) \
- $(PARSERFILES)
-test_transactionparser: $(TEST_TRANSACTIONPARSER_FILES)
- @../../tools/test $(TEST_TRANSACTIONPARSER_FILES) $(BASICFLAGS) $(PARSERFLAGS)
-
-TEST_VERSIONSTR_FILES = \
- versionstr.cc \
- $(BASICFILES)
-test_versionstr: $(TEST_VERSIONSTR_FILES)
- @../../tools/test $(TEST_VERSIONSTR_FILES) $(BASICFLAGS)
-
-TEST_QUERYHANDLERPENTOMINOS_FILES = \
- queryhandlerpentominos.cc \
- tcpsocket.cc \
- $(PARSERFILES) \
- $(BASICFILES)
-test_queryhandlerpentominos: $(TEST_QUERYHANDLERPENTOMINOS_FILES)
- @../../tools/test $(TEST_QUERYHANDLERPENTOMINOS_FILES) $(PARSERFLAGS) $(BASICFLAGS) $(ATF_CFLAGS) $(ATF_LIBS)
+TEST_SOURCE_DEPS = ${pracrod_SOURCES} ${macrotool_SOURCES} \
+ ${EXTRA_DIST}
+TEST_SCRIPT_DIR = $(top_srcdir)/../tools
-TEST_QUERYHANDLERPRACRO_FILES = \
- queryhandlerpracro.cc \
- tcpsocket.cc \
- $(DBFILES) \
- $(PARSERFILES) \
- $(BASICFILES)
-test_queryhandlerpracro: $(TEST_QUERYHANDLERPRACRO_FILES)
- @../../tools/test $(TEST_QUERYHANDLERPRACRO_FILES) $(DBFLAGS) $(PARSERFLAGS) $(BASICFLAGS)
-
-TEST_LUAQUERMAPPER_FILES = \
- luaquerymapper.cc \
- $(BASICFILES)
-test_luaquerymapper: $(TEST_LUAQUERMAPPER_FILES)
- @../../tools/test $(TEST_LUAQUERMAPPER_FILES) $(LUA_LIBS) $(BASICFLAGS)
-
-TEST_TEMPLATEPARSER_FILES = \
- templateparser.cc \
- $(PARSERFILES) \
- $(BASICFILES)
-test_templateparser: $(TEST_TEMPLATEPARSER_FILES)
- @../../tools/test $(TEST_TEMPLATEPARSER_FILES) $(BASICFLAGS) $(PARSERFLAGS)
-
-TEST_MACROPARSER_FILES = \
- macroparser.cc \
- $(PARSERFILES) \
- $(BASICFILES)
-test_macroparser: $(TEST_MACROPARSER_FILES)
- @../../tools/test $(TEST_MACROPARSER_FILES) $(BASICFLAGS) $(PARSERFLAGS)
-
-TEST_SERVER_FILES = \
- server.cc \
- templateparser.cc \
- templatelist.cc \
- templateheaderparser.cc \
- queryhandlerpentominos.cc \
- journal_commit.cc \
- macrolist.cc \
- queryhandlerpracro.cc \
- macroheaderparser.cc \
- versionstr.cc \
- resumeparser.cc \
- luaquerymapper.cc \
- tcpsocket.cc \
- transactionparser.cc \
- widgetgenerator.cc \
- database.cc \
- pracrodao.cc \
- pracrodaotest.cc \
- pracrodaopgsql.cc \
- luaresume.cc \
- macroparser.cc \
- mutex.cc \
- xml_encode_decode.cc \
- $(PARSERFILES) \
- $(BASICFILES)
-test_server: $(TEST_SERVER_FILES)
- @../../tools/test $(TEST_SERVER_FILES) $(BASICFLAGS) $(LUA_LIBS) $(DBFLAGS) $(PARSERFLAGS) $(HTTPD_LIBS) $(HTTPD_CFLAGS)
-
-TEST_PRACRODAOPGSQL_FILES = \
- pracrodaopgsql.cc \
- pracrodao.cc \
- $(BASICFILES)
-test_pracrodaopgsql: $(TEST_PRACRODAOPGSQL_FILES)
- @../../tools/test $(TEST_PRACRODAOPGSQL_FILES) $(DBFLAGS) $(BASICFLAGS)
-
-TEST_XMLENCODEDECODE_FILES = \
- xml_encode_decode.cc
-test_xml_encode_decode: $(TEST_XMLENCODEDECODE_FILES)
- @../../tools/test $(TEST_XMLENCODEDECODE_FILES)
-
-TEST_JOURNALCOMMIT_FILES = \
- journal_commit.cc \
- templateparser.cc \
- $(PARSERFILES) \
- $(BASICFILES)
-test_journal_commit: $(TEST_JOURNALCOMMIT_FILES)
- @../../tools/test $(TEST_JOURNALCOMMIT_FILES) $(PARSERFLAGS) $(BASICFLAGS)
+include ${TEST_SCRIPT_DIR}/Makefile.am.test
-CLEANFILES = $(TESTFILES) $(TESTLOGS) *~
+include Makefile.am.test \ No newline at end of file
diff --git a/server/src/artefact.cc b/server/src/artefact.cc
new file mode 100644
index 0000000..f3e739d
--- /dev/null
+++ b/server/src/artefact.cc
@@ -0,0 +1,188 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set et sw=2 ts=2: */
+/***************************************************************************
+ * artefact.cc
+ *
+ * Tue Jan 5 14:45:34 CET 2010
+ * Copyright 2010 Bent Bisballe Nyeng
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of Pracro.
+ *
+ * Pracro 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 of the License, or
+ * (at your option) any later version.
+ *
+ * Pracro 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 Pracro; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#include "artefact.h"
+
+#include "debug.h"
+#include "configuration.h"
+
+#include "queryparser.h"
+
+Artefact::Artefact()
+{
+#ifndef WITHOUT_ARTEFACT
+
+ PRACRO_DEBUG(artefact, "Creating artefact connection %s : %d\n",
+ Conf::artefact_addr.c_str(), Conf::artefact_port);
+
+ atfh = atf_init();
+ if(!atfh) PRACRO_ERR(artefact, "Out of memory!\n");
+
+ conn = atf_connect(atfh,
+ Conf::artefact_addr.c_str(),
+ Conf::artefact_port,
+ Conf::artefact_use_ssl);
+
+#endif/*WITHOUT_ARTEFACT*/
+}
+
+Artefact::~Artefact()
+{
+#ifndef WITHOUT_ARTEFACT
+
+ atf_disconnect(conn);
+ atf_close(atfh);
+
+#endif/*WITHOUT_ARTEFACT*/
+}
+
+#ifndef WITHOUT_ARTEFACT
+static QueryResult node2result(atf_result_node_t *node, time_t timestamp)
+{
+ QueryResult rnode;
+ rnode.timestamp = timestamp;
+ rnode.source = "artefact";
+
+ if(!node) return rnode;
+
+ struct _atf_result_node_t *child = node->child;
+ while(child) {
+ if(child->value == NULL) {
+ rnode.groups[child->name] = node2result(child, timestamp);
+ } else {
+ rnode.values[child->name] = child->value;
+ }
+ child = child->next;
+ }
+
+ return rnode;
+}
+#endif/*WITHOUT_ARTEFACT*/
+
+QueryResult Artefact::exec(Query &query,
+ std::string patientid,
+ std::string user)
+{
+ QueryResult rroot;
+ rroot.timestamp = 0;
+ rroot.source = "pentominos";
+
+#ifndef WITHOUT_ARTEFACT
+
+ atf_transaction_t* atft = NULL;
+ atf_reply_t *reply = NULL;
+ atf_result_t *result = NULL;
+ atf_result_node_t *root = NULL;
+ atf_status_t status;
+ time_t timestamp;
+ atf_id id;
+
+ if(query.attributes.find("class") == query.attributes.end()) {
+ PRACRO_ERR(artefact, "Missing 'class' attribute!\n");
+ goto aaarg;
+ }
+
+ atft = atf_new_transaction(conn, patientid.c_str());
+ if(!atft) goto aaarg;
+
+ id = atf_add_query(atft, query.attributes["class"].c_str(),
+ FILTER_LATEST, USE_NONE, 0, 0);
+ if(!atft) goto aaarg;
+
+ reply = atf_commit(atft);
+ if(!reply) goto aaarg;
+
+ if(atf_get_num_results(reply, id) != 1) goto aaarg;
+
+ result = atf_get_result(reply, id, 0);
+ if(!result) goto aaarg;
+
+ status = atf_get_result_status(result, NULL, 0);
+ if(status != ATF_STATUS_OK) goto aaarg;
+
+ timestamp = atf_get_result_timestamp(result);
+ rroot.timestamp = timestamp;
+
+ root = atf_get_result_node(result);
+ if(!root) goto aaarg;
+
+ {
+ QueryResult qresult = node2result(root, timestamp);
+ rroot.groups[query.attributes["class"]] = qresult;
+ }
+
+ goto cleanup;
+
+ aaarg:
+ PRACRO_ERR(artefact, "Artefact comm error (%d)!\n", atf_get_last_error(atfh));
+
+ cleanup:
+ if(root) atf_free_result_node(root);
+ if(reply) atf_free_reply(reply);
+ if(atft) atf_free_transaction(atft);
+
+#endif/*WITHOUT_ARTEFACT*/
+
+ return rroot;
+}
+
+
+#ifdef TEST_ARTEFACT
+//deps: configuration.cc debug.cc
+//cflags: $(ATF_CFLAGS) -I..
+//libs: $(ATF_LIBS)
+#include "test.h"
+
+TEST_BEGIN;
+
+pracro_debug_init();
+pracro_debug_parse("+all");
+
+{
+ Artefact atf;
+ Query q;
+ q.attributes["class"] = "echo";
+ QueryResult res = atf.exec(q, "1505050505", "me");
+
+ res.print();
+}
+
+{
+ Conf::artefact_addr = "nowhere_at_all.com";
+ Conf::artefact_port = 10000;
+
+ Artefact atf;
+ Query q;
+ q.attributes["class"] = "echo";
+ QueryResult res = atf.exec(q, "1505050505", "me");
+
+ res.print();
+}
+
+TEST_END;
+
+#endif/*TEST_ARTEFACT*/
diff --git a/server/src/artefact.h b/server/src/artefact.h
new file mode 100644
index 0000000..fa1602d
--- /dev/null
+++ b/server/src/artefact.h
@@ -0,0 +1,54 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set et sw=2 ts=2: */
+/***************************************************************************
+ * artefact.h
+ *
+ * Tue Jan 5 14:45:34 CET 2010
+ * Copyright 2010 Bent Bisballe Nyeng
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of Pracro.
+ *
+ * Pracro 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 of the License, or
+ * (at your option) any later version.
+ *
+ * Pracro 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 Pracro; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#ifndef __PRACRO_ARTEFACT_H__
+#define __PRACRO_ARTEFACT_H__
+
+#include "template.h"
+#include "queryresult.h"
+
+#ifndef WITHOUT_ARTEFACT
+#include <libartefact.h>
+#endif/*WITHOUT_ARTEFACT*/
+
+class Artefact {
+public:
+ Artefact();
+ ~Artefact();
+
+ QueryResult exec(Query &query,
+ std::string patientid,
+ std::string user);
+
+private:
+#ifndef WITHOUT_ARTEFACT
+ atf_handle_t *atfh;
+ atf_connection_t *conn;
+#endif/*WITHOUT_ARTEFACT*/
+};
+
+#endif/*__PRACRO_ARTEFACT_H__*/
diff --git a/server/src/configuration.cc b/server/src/configuration.cc
index c1dcab1..b222639 100644
--- a/server/src/configuration.cc
+++ b/server/src/configuration.cc
@@ -38,12 +38,26 @@ port_t Conf::journal_commit_port = 18112;
time_t Conf::db_max_ttl = 7 * 60 * 60 * 24;
time_t Conf::pentominos_max_ttl = 7 * 60 * 60 * 24;
-std::string Conf::pentominos_addr = "localhost";
-port_t Conf::pentominos_port = 11108;
+std::string Conf::artefact_addr = "localhost";
+port_t Conf::artefact_port = 11108;
+bool Conf::artefact_use_ssl = false;
+
+int Conf::artefact_poolsize = 1;
std::string Conf::database_backend = "pgsql";
std::string Conf::database_addr = "localhost";
std::string Conf::database_user = "pracro";
std::string Conf::database_passwd = "pracro";
+int Conf::database_poolsize = 2;
+
std::string Conf::xml_basedir = XML;
+
+bool Conf::use_ssl = false;
+std::string Conf::ssl_key = "";
+std::string Conf::ssl_cert = "";
+
+int Conf::connection_limit = 42;
+int Conf::connection_timeout = 0;
+
+std::string Conf::session_path = "/tmp";
diff --git a/server/src/configuration.h b/server/src/configuration.h
index 3d9f7f1..8980bfd 100644
--- a/server/src/configuration.h
+++ b/server/src/configuration.h
@@ -45,15 +45,29 @@ namespace Conf {
extern time_t db_max_ttl;
extern time_t pentominos_max_ttl;
- extern std::string pentominos_addr;
- extern port_t pentominos_port;
+ extern std::string artefact_addr;
+ extern port_t artefact_port;
+ extern bool artefact_use_ssl;
+
+ extern int artefact_poolsize;
extern std::string database_backend;
extern std::string database_addr;
extern std::string database_user;
extern std::string database_passwd;
+ extern int database_poolsize;
+
extern std::string xml_basedir;
+
+ extern bool use_ssl;
+ extern std::string ssl_key;
+ extern std::string ssl_cert;
+
+ extern int connection_limit;
+ extern int connection_timeout;
+
+ extern std::string session_path;
};
#endif/*__ARTEFACT_CONFIGURATION_H__*/
diff --git a/server/src/configurationparser.cc b/server/src/configurationparser.cc
index 8247a45..bc10e2b 100644
--- a/server/src/configurationparser.cc
+++ b/server/src/configurationparser.cc
@@ -93,14 +93,26 @@ void ConfigurationParser::reload()
}
try {
- std::string a = lookup("pentominos_addr");
- Conf::pentominos_addr = a;
+ std::string s = lookup("artefact_addr");
+ Conf::artefact_addr = s;
} catch( ... ) {
}
try {
- int p = lookup("pentominos_port");
- Conf::pentominos_port = p;
+ int i = lookup("artefact_port");
+ Conf::artefact_port = i;
+ } catch( ... ) {
+ }
+
+ try {
+ bool b = lookup("artefact_use_ssl");
+ Conf::artefact_use_ssl = b;
+ } catch( ... ) {
+ }
+
+ try {
+ int i = lookup("artefact_poolsize");
+ Conf::artefact_poolsize = i;
} catch( ... ) {
}
@@ -129,10 +141,52 @@ void ConfigurationParser::reload()
}
try {
+ int i = lookup("database_poolsize");
+ Conf::database_poolsize = i;
+ } catch( ... ) {
+ }
+
+ try {
std::string p = lookup("xml_basedir");
Conf::xml_basedir = p;
} catch( ... ) {
}
+
+ try {
+ bool b = lookup("use_ssl");
+ Conf::use_ssl = b;
+ } catch( ... ) {
+ }
+
+ try {
+ std::string s = lookup("ssl_key");
+ Conf::ssl_key = s;
+ } catch( ... ) {
+ }
+
+ try {
+ std::string s = lookup("ssl_cert");
+ Conf::ssl_cert = s;
+ } catch( ... ) {
+ }
+
+ try {
+ int i = lookup("connection_limit");
+ Conf::connection_limit = i;
+ } catch( ... ) {
+ }
+
+ try {
+ int i = lookup("connection_timeout");
+ Conf::connection_timeout = i;
+ } catch( ... ) {
+ }
+
+ try {
+ std::string s = lookup("session_path");
+ Conf::session_path = s;
+ } catch( ... ) {
+ }
}
#ifdef TEST_CONFIGURATIONPARSER
diff --git a/server/src/connection.cc b/server/src/connection.cc
new file mode 100644
index 0000000..ed5a7a9
--- /dev/null
+++ b/server/src/connection.cc
@@ -0,0 +1,339 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set et sw=2 ts=2: */
+/***************************************************************************
+ * connection.cc
+ *
+ * Fri May 7 11:35:44 CEST 2010
+ * Copyright 2010 Bent Bisballe Nyeng
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of Pracro.
+ *
+ * Pracro 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 of the License, or
+ * (at your option) any later version.
+ *
+ * Pracro 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 Pracro; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#include "connection.h"
+
+#include "transactionhandler.h"
+#include "xml_encode_decode.h"
+
+static std::string error_box(std::string message)
+{
+ std::string errorbox =
+ "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<pracro version=\"1.0\">\n"
+ " <error>" + message + "</error>\n"
+ "</pracro>\n";
+ return errorbox;
+}
+
+#ifdef TEST_CONNECTION
+static bool did_commit = false;
+#endif
+
+Connection::Connection(Environment &e, std::string sid, bool c, bool d)
+ : env(e), parser(&transaction)
+{
+ PRACRO_DEBUG(connection, "[%p] CREATE\n", this);
+
+ sessionid = sid;
+ docommit = c;
+ dodiscard = d;
+
+#ifdef TEST_CONNECTION
+ did_commit = false;
+#endif
+
+}
+
+Connection::~Connection()
+{
+ PRACRO_DEBUG(connection, "[%p] DESTROY\n", this);
+}
+
+void Connection::commit(Session *session)
+{
+ if(docommit) {
+ session->commit();
+ env.sessions.deleteSession(session->id());
+ sessionid = "";
+#ifdef TEST_CONNECTION
+ did_commit = true;
+#endif
+ }
+}
+
+void Connection::discard(Session *session)
+{
+ if(dodiscard) {
+ session->discard();
+ env.sessions.deleteSession(session->id());
+ sessionid = "";
+ }
+}
+
+bool Connection::handle(const char *data, size_t size)
+{
+ Session *session = NULL;
+ if(sessionid == "") {
+ // Create new session
+ session = env.sessions.newSession();
+ } else {
+ // Attach to old session
+ session = env.sessions.session(sessionid);
+
+ // Session didn't exist - create a new one anyway.
+ if(session == NULL) session = env.sessions.newSession();
+ }
+
+ if(session == NULL) {
+ PRACRO_ERR(connection, "New session could not be created.");
+ response = error_box(xml_encode("New session could not be created."));
+ return true;
+ }
+
+ sessionid = session->id();
+
+ try {
+
+ if(!data || !size) {
+ commit(session);
+ discard(session);
+ return true;
+ }
+
+ if(parser.parse(data, size)) {
+ {
+ SessionAutolock lock(*session);
+ response = handleTransaction(transaction, env, *session);
+ }
+
+ commit(session);
+ discard(session);
+ return true;
+ }
+ } catch(...) {
+ PRACRO_ERR(server, "Failed to parse data!\n");
+ response = error_box(xml_encode("XML Parse error."));
+ return true;
+ }
+
+ return false;
+}
+
+std::string Connection::getResponse()
+{
+ return response;
+}
+
+std::string Connection::getSessionID()
+{
+ return sessionid;
+}
+
+#ifdef TEST_CONNECTION
+//deps: debug.cc transactionparser.cc session.cc xml_encode_decode.cc saxparser.cc transactionhandler.cc journalwriter.cc mutex.cc templateparser.cc exception.cc configuration.cc macroparser.cc semaphore.cc entitylist.cc luaquerymapper.cc inotify.cc log.cc queryhandlerpentominos.cc widgetgenerator.cc queryhandlerpracro.cc resumeparser.cc journal_commit.cc versionstr.cc luaresume.cc luautil.cc artefact.cc environment.cc database.cc macrolist.cc templatelist.cc pracrodao.cc templateheaderparser.cc macroheaderparser.cc pracrodaotest.cc pracrodaopgsql.cc
+//cflags: -DWITHOUT_DATABASE -DWITHOUT_ARTEFACT -I.. $(LUA_CFLAGS) $(EXPAT_CFLAGS) $(PTHREAD_CFLAGS) $(PQXX_CXXFLAGS)
+//libs: $(LUA_LIBS) $(EXPAT_LIBS) $(PTHREAD_LIBS) $(PQXX_LIBS)
+#include "test.h"
+
+static char xml_request[] =
+"<?xml version='1.0' encoding='UTF-8'?>\n"
+"<pracro version=\"1.0\" user=\"testuser\" cpr=\"1505050505\">\n"
+" <request macro=\"test\" template=\"test\"/>\n"
+"</pracro>\n"
+ ;
+
+static char xml_commit[] =
+"<?xml version='1.0' encoding='UTF-8'?>\n"
+"<pracro version=\"1.0\" user=\"testuser\" cpr=\"1505050505\">\n"
+" <commit version=\"\" macro=\"referral\" template=\"amd_forunders\" >\n"
+" <field value=\"Some docs\" name=\"referral.doctor\"/>\n"
+" <field value=\"DIMS\" name=\"referral.diagnosecode\"/>\n"
+" <field value=\"Avs\" name=\"referral.diagnose\"/>\n"
+" </commit>\n"
+"</pracro>\n"
+ ;
+
+static char xml_commit_p1[] =
+"<?xml version='1.0' encoding='UTF-8'?>\n"
+"<pracro version=\"1.0\" user=\"testuser\" cpr=\"1505050505\">\n"
+" <commit version=\"\" macro=\"referral\" template=\"amd_forunders\" >\n"
+" <field value=\"Some docs\" name=\"referral.doctor\"/>\n"
+" <field value=\"DIMS\" name=\"referral.diagn"
+ ;
+
+static char xml_commit_p2[] =
+"ose\"/>\n"
+" </commit>\n"
+"</pracro>\n"
+ ;
+
+TEST_BEGIN;
+
+Environment env;
+std::string sid;
+
+// Without data
+{
+ Connection con(env, "", false);
+ TEST_TRUE(con.handle("", 0), "Test handler return value.");
+ TEST_EQUAL_STR(con.getResponse(), "", "Test response value.");
+ sid = con.getSessionID();
+ TEST_NOTEQUAL_STR(sid, "", "Test new session id.");
+ TEST_FALSE(did_commit, "No commit.");
+}
+
+{
+ Connection con(env, sid, false);
+ TEST_TRUE(con.handle("", 0), "Test handler return value.");
+ TEST_EQUAL_STR(con.getResponse(), "", "Test response value.");
+ TEST_NOTEQUAL_STR(con.getSessionID(), "", "Test existing session id.");
+ TEST_EQUAL_STR(con.getSessionID(), sid, "Test existing session id.");
+ TEST_FALSE(did_commit, "No commit.");
+}
+
+{
+ Connection con(env, sid, true);
+ TEST_TRUE(con.handle("", 0), "Test handler return value.");
+ TEST_EQUAL_STR(con.getResponse(), "", "Test response value.");
+ TEST_EQUAL_STR(con.getSessionID(), "", "Test existing session id.");
+ TEST_TRUE(did_commit, "Commit.");
+}
+
+{
+ Connection con(env, sid, false);
+ TEST_TRUE(con.handle("", 0), "Test handler return value.");
+ TEST_EQUAL_STR(con.getResponse(), "", "Test response value.");
+ TEST_NOTEQUAL_STR(con.getSessionID(), "", "Test existing session id.");
+ TEST_NOTEQUAL_STR(con.getSessionID(), sid, "Test new session id.");
+ TEST_FALSE(did_commit, "No commit.");
+}
+
+// With commit partial data
+{
+ Connection con(env, "", false);
+ TEST_FALSE(con.handle(xml_commit_p1, sizeof(xml_commit_p1) - 1),
+ "Test handler return value.");
+ sid = con.getSessionID();
+ TEST_NOTEQUAL_STR(sid, "", "Test new session id.");
+ TEST_FALSE(did_commit, "No commit.");
+ TEST_EQUAL_STR(con.getResponse(), "", "Test response value.");
+ TEST_TRUE(con.handle(xml_commit_p2, sizeof(xml_commit_p2) - 1),
+ "Test handler return value.");
+ TEST_EQUAL_STR(con.getSessionID(), sid, "Test session id.");
+ TEST_NOTEQUAL_STR(con.getResponse(), "", "Test response value.");
+ TEST_FALSE(did_commit, "No commit.");
+}
+
+// With commit partial data and journal commit
+{
+ Connection con(env, "", true);
+ TEST_FALSE(con.handle(xml_commit_p1, sizeof(xml_commit_p1) - 1),
+ "Test handler return value.");
+ sid = con.getSessionID();
+ TEST_NOTEQUAL_STR(sid, "", "Test new session id.");
+ TEST_EQUAL_STR(con.getResponse(), "", "Test response value.");
+ TEST_FALSE(did_commit, "No commit.");
+ TEST_TRUE(con.handle(xml_commit_p2, sizeof(xml_commit_p2) - 1),
+ "Test handler return value.");
+ TEST_EQUAL_STR(con.getSessionID(), "", "Test session id.");
+ TEST_TRUE(did_commit, "No commit.");
+ TEST_NOTEQUAL_STR(con.getResponse(), "", "Test response value.");
+}
+
+// With commit data
+{
+ Connection con(env, "", false);
+ TEST_TRUE(con.handle(xml_commit, sizeof(xml_commit) - 1),
+ "Test handler return value.");
+ sid = con.getSessionID();
+ TEST_NOTEQUAL_STR(sid, "", "Test new session id.");
+ TEST_NOTEQUAL_STR(con.getResponse(), "", "Test response value.");
+ TEST_FALSE(did_commit, "No commit.");
+}
+
+{
+ Connection con(env, sid, false);
+ TEST_TRUE(con.handle(xml_commit, sizeof(xml_commit) - 1),
+ "Test handler return value.");
+ TEST_NOTEQUAL_STR(con.getResponse(), "", "Test response value.");
+ TEST_NOTEQUAL_STR(con.getSessionID(), "", "Test existing session id.");
+ TEST_EQUAL_STR(con.getSessionID(), sid, "Test existing session id.");
+ TEST_FALSE(did_commit, "No commit.");
+}
+
+{
+ Connection con(env, sid, true);
+ TEST_TRUE(con.handle(xml_commit, sizeof(xml_commit) - 1),
+ "Test handler return value.");
+ TEST_NOTEQUAL_STR(con.getResponse(), "", "Test response value.");
+ TEST_EQUAL_STR(con.getSessionID(), "", "Test existing session id.");
+ TEST_TRUE(did_commit, "Commit.");
+}
+
+{
+ Connection con(env, sid, false);
+ TEST_TRUE(con.handle(xml_commit, sizeof(xml_commit) - 1),
+ "Test handler return value.");
+ TEST_NOTEQUAL_STR(con.getResponse(), "", "Test response value.");
+ TEST_NOTEQUAL_STR(con.getSessionID(), "", "Test existing session id.");
+ TEST_NOTEQUAL_STR(con.getSessionID(), sid, "Test new session id.");
+ TEST_FALSE(did_commit, "No commit.");
+}
+
+// With request data
+{
+ Connection con(env, "", false);
+ TEST_TRUE(con.handle(xml_request, sizeof(xml_request) - 1),
+ "Test handler return value.");
+ TEST_NOTEQUAL_STR(con.getResponse(), "", "Test response value.");
+ sid = con.getSessionID();
+ TEST_NOTEQUAL_STR(sid, "", "Test new session id.");
+ TEST_FALSE(did_commit, "No commit.");
+}
+
+{
+ Connection con(env, sid, false);
+ TEST_TRUE(con.handle(xml_request, sizeof(xml_request) - 1),
+ "Test handler return value.");
+ TEST_NOTEQUAL_STR(con.getResponse(), "", "Test response value.");
+ TEST_NOTEQUAL_STR(con.getSessionID(), "", "Test existing session id.");
+ TEST_EQUAL_STR(con.getSessionID(), sid, "Test existing session id.");
+ TEST_FALSE(did_commit, "No commit.");
+}
+
+{
+ Connection con(env, sid, true);
+ TEST_TRUE(con.handle(xml_request, sizeof(xml_request) - 1),
+ "Test handler return value.");
+ TEST_NOTEQUAL_STR(con.getResponse(), "", "Test response value.");
+ TEST_EQUAL_STR(con.getSessionID(), "", "Test existing session id.");
+ TEST_TRUE(did_commit, "Commit.");
+}
+
+{
+ Connection con(env, sid, false);
+ TEST_TRUE(con.handle(xml_request, sizeof(xml_request) - 1),
+ "Test handler return value.");
+ TEST_NOTEQUAL_STR(con.getSessionID(), "", "Test existing session id.");
+ TEST_NOTEQUAL_STR(con.getSessionID(), sid, "Test new session id.");
+ TEST_FALSE(did_commit, "No commit.");
+}
+
+TEST_END;
+
+#endif/*TEST_CONNECTION*/
diff --git a/server/src/connection.h b/server/src/connection.h
new file mode 100644
index 0000000..61997da
--- /dev/null
+++ b/server/src/connection.h
@@ -0,0 +1,63 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set et sw=2 ts=2: */
+/***************************************************************************
+ * connection.h
+ *
+ * Fri May 7 11:35:43 CEST 2010
+ * Copyright 2010 Bent Bisballe Nyeng
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of Pracro.
+ *
+ * Pracro 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 of the License, or
+ * (at your option) any later version.
+ *
+ * Pracro 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 Pracro; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#ifndef __PRACRO_CONNECTION_H__
+#define __PRACRO_CONNECTION_H__
+
+#include <string>
+#include "environment.h"
+#include "transaction.h"
+#include "transactionparser.h"
+
+class Session;
+
+class Connection {
+public:
+ Connection(Environment &e, std::string sessionid, bool commit, bool discard);
+ ~Connection();
+
+ bool handle(const char *data, size_t size);
+
+ std::string getResponse();
+ std::string getSessionID();
+
+private:
+ void commit(Session *session);
+ void discard(Session *session);
+
+ std::string sessionid;
+ bool docommit;
+ bool dodiscard;
+ Environment &env;
+
+ Transaction transaction;
+ TransactionParser parser;
+
+ std::string response;
+};
+
+#endif/*__PRACRO_CONNECTION_H__*/
diff --git a/server/src/connectionpool.cc b/server/src/connectionpool.cc
new file mode 100644
index 0000000..e2b6bfc
--- /dev/null
+++ b/server/src/connectionpool.cc
@@ -0,0 +1,162 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set et sw=2 ts=2: */
+/***************************************************************************
+ * connectionpool.cc
+ *
+ * Wed Dec 16 12:20:44 CET 2009
+ * Copyright 2009 Bent Bisballe Nyeng
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of Pracro.
+ *
+ * Pracro 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 of the License, or
+ * (at your option) any later version.
+ *
+ * Pracro 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 Pracro; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#include "connectionpool.h"
+
+//
+// Implementation is in the header file.
+//
+
+#ifdef TEST_CONNECTIONPOOL
+//deps: mutex.cc semaphore.cc
+//cflags: $(PTHREAD_CFLAGS)
+//libs: $(PTHREAD_LIBS)
+#include <test.h>
+#include <unistd.h>
+#include <pthread.h>
+
+static void* thread_run(void *data)
+{
+ ConnectionPool<int> *pool = (ConnectionPool<int>*)data;
+
+ int db1 = pool->borrow();
+ int db2 = pool->borrow();
+ int db3 = pool->borrow();
+ int db4 = pool->borrow();
+
+ usleep(100);
+
+ pool->giveBack(db1);
+ pool->giveBack(db2);
+ pool->giveBack(db3);
+ pool->giveBack(db4);
+
+ return NULL;
+}
+
+static void* thread_run_clear_test(void *data)
+{
+ ConnectionPool<int> *pool = (ConnectionPool<int>*)data;
+ pool->giveBack(1);
+ pool->giveBack(2);
+
+ sleep(1);
+
+ pool->giveBack(3);
+ pool->giveBack(4);
+
+ return NULL;
+}
+
+TEST_BEGIN;
+
+ConnectionPool<int> pool;
+
+int db1 = 1;
+int db2 = 2;
+int db3 = 3;
+int db4 = 4;
+
+pool.add(db1);
+pool.add(db2);
+pool.add(db3);
+pool.add(db4);
+
+TEST_TRUE(pool.testFree(db1), "Testing if db1 is free.");
+TEST_TRUE(pool.testFree(db2), "Testing if db2 is free.");
+TEST_TRUE(pool.testFree(db3), "Testing if db3 is free.");
+TEST_TRUE(pool.testFree(db4), "Testing if db4 is free.");
+TEST_EQUAL(pool.numFree(), 4, "Testing number of free databases.");
+
+int b_db1 = pool.borrow();
+TEST_FALSE(pool.testFree(b_db1), "Testing if borrowed db is free.");
+
+int b_db2 = pool.borrow();
+TEST_NOTEQUAL(b_db1, b_db2, "Testing if borrowed db is unique.");
+
+pool.giveBack(b_db1);
+TEST_TRUE(pool.testFree(b_db1), "Testing if returned db is free.");
+pool.giveBack(b_db2);
+
+TEST_EQUAL(pool.numFree(), 4, "Testing number of free databases.");
+
+{
+ pthread_attr_t attr;
+ pthread_t tid;
+ pthread_attr_init(&attr);
+ pthread_create(&tid, &attr, thread_run, &pool);
+
+ while(pool.numFree() > 0) { usleep(10); }
+
+ int b_db3 = pool.borrow();
+ TEST_FALSE(pool.testFree(b_db3), "Testing if returned db is free (semaphore test).");
+ pool.giveBack(db3);
+
+ pthread_join(tid, NULL);
+ pthread_attr_destroy(&attr);
+}
+
+TEST_EQUAL(pool.numFree(), 4, "Testing if all database are now available again");
+
+{
+ TEST_EQUAL(pool.numFree(), 4, "Testing if autoborrower has not yet borrowed a db.");
+ AutoBorrower<int> b(pool);
+ TEST_EQUAL(pool.numFree(), 3, "Testing if autoborrower has borrowed a db.");
+ TEST_FALSE(pool.testFree(b.get()), "Testing if the autoborrowed db is actually taken.");
+}
+TEST_EQUAL(pool.numFree(), 4, "Testing if autoborrower has returned the db.");
+
+// Force remove all elements.
+pool.borrow();
+pool.clear(true);
+TEST_EQUAL(pool.numFree(), 0, "Testing number of free databases.");
+
+// Add them again.
+pool.add(db1);
+pool.add(db2);
+pool.add(db3);
+pool.add(db4);
+TEST_EQUAL(pool.numFree(), 4, "Testing number of free databases.");
+
+pool.borrow();
+pool.borrow();
+pool.borrow();
+pool.borrow();
+
+{
+ pthread_attr_t attr;
+ pthread_t tid;
+ pthread_attr_init(&attr);
+ pthread_create(&tid, &attr, thread_run_clear_test, &pool);
+ pool.clear(false);
+ pthread_join(tid, NULL);
+ pthread_attr_destroy(&attr);
+}
+
+TEST_END;
+
+#endif/*TEST_CONNECTIONPOOL*/
diff --git a/server/src/connectionpool.h b/server/src/connectionpool.h
new file mode 100644
index 0000000..33473e5
--- /dev/null
+++ b/server/src/connectionpool.h
@@ -0,0 +1,226 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set et sw=2 ts=2: */
+/***************************************************************************
+ * connectionpool.h
+ *
+ * Wed Dec 16 12:20:44 CET 2009
+ * Copyright 2009 Bent Bisballe Nyeng
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of Pracro.
+ *
+ * Pracro 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 of the License, or
+ * (at your option) any later version.
+ *
+ * Pracro 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 Pracro; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#ifndef __PRACRO_CONNECTIONPOOL_H__
+#define __PRACRO_CONNECTIONPOOL_H__
+
+#include <list>
+
+#include "mutex.h"
+#include "semaphore.h"
+
+template <class T>
+class ConnectionPool {
+public:
+ void add(T t);
+ void remove(T t);
+
+ bool testFree(T t);
+ int numFree();
+
+ T borrow();
+ void giveBack(T t);
+
+ std::list<T> clear(bool force = true);
+
+private:
+ bool contains(std::list<T> &list, T t);
+
+ Semaphore semaphore;
+ Mutex mutex;
+ std::list<T> active;
+ std::list<T> passive;
+};
+
+template <class T>
+class AutoBorrower {
+public:
+ AutoBorrower(ConnectionPool<T> &pool);
+ ~AutoBorrower();
+
+ T get();
+
+private:
+ ConnectionPool<T> &pool;
+ T t;
+};
+
+
+//
+// Implementation is below
+//
+
+template <class T>
+void ConnectionPool<T>::add(T t)
+{
+ MutexAutolock lock(mutex);
+
+ passive.push_back(t);
+ semaphore.post();
+
+}
+
+template <class T>
+bool ConnectionPool<T>::contains(std::list<T> &list, T t)
+{
+ typename std::list<T>::iterator i = list.begin();
+ while(i != list.end()) {
+ if(*i == t) return true;
+ i++;
+ }
+
+ return false;
+}
+
+template <class T>
+void ConnectionPool<T>::remove(T t)
+{
+ MutexAutolock lock(mutex);
+
+ if(contains(passive, t)) {
+ semaphore.post();
+ passive.remove(t);
+ }
+
+}
+
+template <class T>
+bool ConnectionPool<T>::testFree(T t)
+{
+ bool testfree = false;
+
+ MutexAutolock lock(mutex);
+ testfree = contains(passive, t);
+
+ return testfree;
+}
+
+template <class T>
+int ConnectionPool<T>::numFree()
+{
+ int num;
+
+ MutexAutolock lock(mutex);
+ num = passive.size();
+
+ return num;
+}
+
+template <class T>
+T ConnectionPool<T>::borrow()
+{
+ T t = NULL;
+
+ semaphore.wait();
+
+ {
+ MutexAutolock lock(mutex);
+
+ t = passive.front();
+ passive.remove(t);
+ active.push_back(t);
+ }
+
+ return t;
+}
+
+template <class T>
+void ConnectionPool<T>::giveBack(T t)
+{
+ MutexAutolock lock(mutex);
+
+ if(contains(active, t)) {
+ active.remove(t);
+ passive.push_back(t);
+ semaphore.post();
+ }
+}
+
+template <class T>
+std::list<T> ConnectionPool<T>::clear(bool force)
+{
+ typename std::list<T> lst;
+
+ if(force == false) {
+ size_t num = 0;
+ {
+ MutexAutolock lock(mutex);
+ num = active.size() + passive.size();
+ }
+
+ while(num) {
+ borrow();
+ num--;
+ }
+ }
+
+ {
+ MutexAutolock lock(mutex);
+
+ typename std::list<T>::iterator i;
+
+ i = active.begin();
+ while(i != active.end()) {
+ lst.push_back(*i);
+ // i = active.erase(i);
+ semaphore.post();
+ i++;
+ }
+ active.clear();
+
+ i = passive.begin();
+ while(i != passive.end()) {
+ lst.push_back(*i);
+ // i = passive.erase(i);
+ i++;
+ }
+ passive.clear();
+ }
+
+ return lst;
+}
+
+template <class T>
+AutoBorrower<T>::AutoBorrower(ConnectionPool<T> &p)
+ : pool(p)
+{
+ t = pool.borrow();
+}
+
+template <class T>
+AutoBorrower<T>::~AutoBorrower()
+{
+ pool.giveBack(t);
+}
+
+template <class T>
+T AutoBorrower<T>::get()
+{
+ return t;
+}
+
+#endif/*__PRACRO_CONNECTIONPOOL_H__*/
diff --git a/server/src/debug.cc b/server/src/debug.cc
index 54a2191..8bb45db 100644
--- a/server/src/debug.cc
+++ b/server/src/debug.cc
@@ -37,7 +37,7 @@
#define NELEM(x) (sizeof(x)/sizeof((x)[0]))
struct __pracro_debug_channel
{
- char name[16];
+ char name[64];
unsigned flags;
};
diff --git a/server/src/entitylist.cc b/server/src/entitylist.cc
new file mode 100644
index 0000000..3ec15a5
--- /dev/null
+++ b/server/src/entitylist.cc
@@ -0,0 +1,331 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set et sw=2 ts=2: */
+/***************************************************************************
+ * entitylist.cc
+ *
+ * Thu Jan 14 14:17:34 CET 2010
+ * Copyright 2010 Bent Bisballe Nyeng
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of Pracro.
+ *
+ * Pracro 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 of the License, or
+ * (at your option) any later version.
+ *
+ * Pracro 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 Pracro; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#include "entitylist.h"
+
+#include <sys/types.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <vector>
+
+#include "debug.h"
+
+static inline bool isdir(std::string name)
+{
+ struct stat s;
+ stat(name.c_str(), &s);
+ return S_ISDIR(s.st_mode);
+}
+
+static inline bool isfile(std::string name)
+{
+ struct stat s;
+ stat(name.c_str(), &s);
+ return S_ISREG(s.st_mode);
+}
+
+static std::vector<std::string> listdir(std::string path)
+{
+ std::vector<std::string> files;
+
+ DIR* dir = opendir(path.c_str());
+ if(!dir) {
+ PRACRO_ERR(entitylist, "Could not open directory: %s\n", path.c_str());
+ return files;
+ }
+
+ struct dirent *d;
+ while((d = readdir(dir)) != 0) {
+ std::string name = d->d_name;
+
+ if(name == "." || name == "..") continue;
+
+ if(isdir(path + "/" + name)) {
+ std::vector<std::string> sub = listdir(path + "/" + name);
+ files.insert(files.end(), sub.begin(), sub.end());
+ continue;
+ }
+
+ if(isfile(path + "/" + name)) {
+ if(name.length() >= 4 && name.substr(name.length() - 4) == ".xml")
+ files.push_back(path + "/" + name);
+ }
+ }
+ closedir(dir);
+
+ return files;
+}
+
+EntityList::EntityList(std::string entitypath, std::string entityname)
+{
+ MutexAutolock lock(mutex);
+
+ this->entityname = entityname;
+ this->entitypath = entitypath;
+}
+
+EntityList::~EntityList()
+{
+}
+
+void EntityList::rescan()
+{
+ clear();
+ inotify.clear();
+
+ inotify.addDirectory(entitypath, WATCH_DEEP_FOLLOW,
+ IN_CLOSE_WRITE |
+ IN_MOVED_FROM | IN_MOVED_TO | IN_MOVE_SELF |
+ IN_DELETE | IN_DELETE_SELF |
+ IN_CREATE);
+
+ std::vector<std::string> entitys = listdir(entitypath);
+ std::vector<std::string>::iterator i = entitys.begin();
+ while(i != entitys.end()) {
+ addFile(*i);
+ i++;
+ }
+
+ {
+ iterator i = begin();
+ while(i != end()) {
+ EntityListItem::iterator j = i->second.begin();
+ while(j != i->second.end()) {
+ PRACRO_DEBUG(entitylist, "%s - v%s file: %s\n",
+ i->first.c_str(),
+ ((std::string)j->first).c_str(),
+ j->second.c_str());
+ j++;
+ }
+ i++;
+ }
+ }
+}
+
+bool EntityList::removeFile(std::string file)
+{
+ // Check if the file is already in the tree.
+ iterator i = begin();
+ while(i != end()) {
+ EntityListItem::iterator j = i->second.begin();
+ while(j != i->second.end()) {
+ if(file == j->second) {
+ PRACRO_DEBUG(entitylist, "Removing file: %s\n", file.c_str());
+ i->second.erase(j);
+ if(i->second.size() == 0) erase(i);
+ return true;
+ }
+ j++;
+ }
+ i++;
+ }
+
+ return false;
+}
+
+void EntityList::updateFile(std::string file)
+{
+ removeFile(file);
+ addFile(file);
+}
+
+void EntityList::updateList()
+{
+ while(inotify.hasEvents()) {
+ INotify::Event event = inotify.getNextEvent();
+
+ PRACRO_DEBUG(entitylist, "Handling event %s on %s, with param %s\n",
+ event.maskstr().c_str(),
+ event.name().c_str(),
+ event.file().c_str());
+
+ if(event.isDir()) {
+ if(event.isCreateEvent()) {
+ // A new directory was ceated. Scan it for files.
+ std::vector<std::string> entitys = listdir(event.name()+"/"+event.file());
+ std::vector<std::string>::iterator i = entitys.begin();
+ while(i != entitys.end()) {
+ updateFile(*i);
+ i++;
+ }
+ }
+
+ if(event.isMoveSelfEvent()) rescan();
+ if(event.isDeleteSelfEvent()) rescan();
+ if(event.isDeleteEvent()) rescan();
+ if(event.isMovedFromEvent()) rescan();
+ if(event.isMovedToEvent()) rescan();
+
+ } else {
+ if(event.isCloseWriteEvent()) updateFile(event.name()+"/"+event.file());
+ if(event.isMovedFromEvent()) removeFile(event.name()+"/"+event.file());
+ if(event.isMovedToEvent()) updateFile(event.name()+"/"+event.file());
+ if(event.isDeleteEvent()) removeFile(event.name()+"/"+event.file());
+ }
+ }
+}
+
+std::string EntityList::getLatestVersion(std::string entity) throw(Exception)
+{
+ MutexAutolock lock(mutex);
+
+ updateList();
+
+ if(find(entity) == end()) {
+ throw Exception("Entity ("+entityname+") ["+entity+"] does not exist");
+ }
+
+ EntityListItem mli = (*this)[entity];
+ if(mli.size() == 0) {
+ throw Exception("Entity ("+entityname+") ["+entity+"] does not exist.");
+ }
+
+ PRACRO_DEBUG(entitylist, "Search for %s - found %s v%s\n",
+ entity.c_str(),
+ mli.begin()->second.c_str(),
+ ((std::string)mli.begin()->first).c_str());
+
+ return mli.begin()->second;
+}
+
+void EntityList::insertEntity(std::string entity, std::string version, std::string file)
+{
+ std::pair<VersionStr, std::string> p(VersionStr(version), file);
+ (*this)[entity].insert(p);
+}
+
+#ifdef TEST_ENTITYLIST
+//deps: inotify.cc debug.cc mutex.cc exception.cc versionstr.cc log.cc
+//cflags: -I.. $(PTHREAD_CFLAGS)
+//libs: $(PTHREAD_LIBS)
+#include "test.h"
+
+#include <string.h>
+
+#define _DIR "/tmp/entitylist_test_dir"
+
+class TestList : public EntityList {
+public:
+ TestList(std::string path) : EntityList(path, "test") { rescan(); }
+
+private:
+ void addFile(std::string file)
+ {
+ char version[32];
+ FILE *fp = fopen(file.c_str(), "r");
+ if(!fp) return;
+ memset(version, 0, sizeof(version));
+ fread(version, sizeof(version), 1, fp);
+ fclose(fp);
+
+ fprintf(stderr, "Inserting: %s\n", version);
+ insertEntity("test", version, file);
+ }
+};
+
+bool createfile(TestList &lst, std::string filename,
+ std::string name, std::string version)
+{
+ FILE *fp = fopen(filename.c_str(), "w");
+ if(!fp) return false;
+ fprintf(fp, "%s", version.c_str());
+ fclose(fp);
+ return true;
+}
+
+TEST_BEGIN;
+
+pracro_debug_parse("-all,+entitylist");
+
+if(mkdir(_DIR, 0777) == -1) TEST_FATAL("Could not create test dir.");
+
+TestList lst(_DIR);
+
+TEST_EXCEPTION(lst.getLatestVersion("test"), Exception,
+ "Test lookup of macro in empty tree.");
+
+if(!createfile(lst, _DIR"/file1.xml", "test", "1.0"))
+ TEST_FATAL("Unable to write to the file");
+
+TEST_EQUAL_STR(lst.getLatestVersion("test"), _DIR"/file1.xml", "Test");
+
+if(!createfile(lst, _DIR"/file2.xml", "test", "2.0"))
+ TEST_FATAL("Unable to write to the file");
+
+TEST_EQUAL_STR(lst.getLatestVersion("test"), _DIR"/file2.xml", "Test");
+
+unlink(_DIR"/file2.xml");
+
+TEST_EQUAL_STR(lst.getLatestVersion("test"), _DIR"/file1.xml", "Test");
+
+if(mkdir(_DIR"/more", 0777) == -1) TEST_FATAL("Could not create test dir.");
+
+if(!createfile(lst, _DIR"/more/file1.xml", "test", "3.0"))
+ TEST_FATAL("Unable to write to the file");
+
+TEST_EQUAL_STR(lst.getLatestVersion("test"), _DIR"/more/file1.xml", "Test");
+
+if(!createfile(lst, _DIR"/more/file2.xml", "test", "4.0"))
+ TEST_FATAL("Unable to write to the file");
+
+TEST_EQUAL_STR(lst.getLatestVersion("test"), _DIR"/more/file2.xml", "Test");
+
+unlink(_DIR"/more/file2.xml");
+
+TEST_EQUAL_STR(lst.getLatestVersion("test"), _DIR"/more/file1.xml", "Test");
+
+rename(_DIR"/more/file1.xml", _DIR"/more/file2.xml");
+
+TEST_EQUAL_STR(lst.getLatestVersion("test"), _DIR"/more/file2.xml", "Test");
+
+rename(_DIR"/more", _DIR"/more2");
+
+TEST_EQUAL_STR(lst.getLatestVersion("test"), _DIR"/more2/file2.xml", "Test");
+
+rename(_DIR"/more2/file2.xml", _DIR"/file3.xml");
+
+TEST_EQUAL_STR(lst.getLatestVersion("test"), _DIR"/file3.xml", "Test");
+
+unlink(_DIR"/file3.xml");
+
+rmdir(_DIR"/more2");
+
+TEST_EQUAL_STR(lst.getLatestVersion("test"), _DIR"/file1.xml", "Test");
+
+unlink(_DIR"/file1.xml");
+
+TEST_EXCEPTION(lst.getLatestVersion("test"), Exception, "Test lookup of missing macro.");
+
+rmdir(_DIR);
+
+TEST_EXCEPTION(lst.getLatestVersion("test"), Exception, "Test lookup in missing folder.");
+
+TEST_END;
+
+#endif/*TEST_ENTITYLIST*/
diff --git a/server/src/entitylist.h b/server/src/entitylist.h
new file mode 100644
index 0000000..3bcdfd0
--- /dev/null
+++ b/server/src/entitylist.h
@@ -0,0 +1,91 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set et sw=2 ts=2: */
+/***************************************************************************
+ * entitylist.h
+ *
+ * Thu Jan 14 14:17:34 CET 2010
+ * Copyright 2010 Bent Bisballe Nyeng
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of Pracro.
+ *
+ * Pracro 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 of the License, or
+ * (at your option) any later version.
+ *
+ * Pracro 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 Pracro; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#ifndef __PRACRO_ENTITYLIST_H__
+#define __PRACRO_ENTITYLIST_H__
+
+#include <map>
+#include <string>
+
+#include "versionstr.h"
+#include "mutex.h"
+
+#include "inotify.h"
+
+#include "exception.h"
+
+/**
+ * The Items contained in the EntityList.
+ */
+typedef std::multimap<VersionStr, std::string> EntityListItem;
+
+/**
+ * The EntityList class is intended for entity file caching, so that all entitys
+ * do not need to be parsed on each entity query.
+ * It builds a list of entitys and versions based on the informations read from
+ * the EntityHeaderParser.
+ * This means that just because a entity gets into the list doesn't means that it
+ * will validate as a correct entity (not even nessecarily correct XML).
+ */
+class EntityList : public std::map<std::string, EntityListItem > {
+public:
+ /**
+ * Constructor.
+ * @param entitypath A std::string containing the path in which we should look
+ * for xml files.
+ */
+ EntityList(std::string entitypath, std::string entityname);
+ virtual ~EntityList();
+
+ /**
+ * Convenience method, to gain the filename of the latest version of a given entity.
+ * This method throws an Exception if the entity does not exist in the tree.
+ * @param entity A std::string containing the name of the wanted entity.
+ * @return A std::string containing the file containing the entity with full path
+ * included.
+ */
+ std::string getLatestVersion(std::string entity) throw(Exception);
+
+protected:
+ void rescan();
+ void insertEntity(std::string entity, std::string version, std::string file);
+
+private:
+ virtual void addFile(std::string file) = 0;
+
+ bool removeFile(std::string file);
+ void updateFile(std::string file);
+ void updateList();
+
+ Mutex mutex;
+ INotify inotify;
+
+ std::string entityname;
+ std::string entitypath;
+};
+
+#endif/*__PRACRO_ENTITYLIST_H__*/
diff --git a/server/src/environment.cc b/server/src/environment.cc
new file mode 100644
index 0000000..9904afc
--- /dev/null
+++ b/server/src/environment.cc
@@ -0,0 +1,85 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set et sw=2 ts=2: */
+/***************************************************************************
+ * environment.cc
+ *
+ * Tue Jan 5 11:41:23 CET 2010
+ * Copyright 2010 Bent Bisballe Nyeng
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of Pracro.
+ *
+ * Pracro 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 of the License, or
+ * (at your option) any later version.
+ *
+ * Pracro 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 Pracro; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#include "environment.h"
+
+#include "configuration.h"
+#include "database.h"
+
+Environment::Environment()
+ : macrolist(Conf::xml_basedir + "/macros"),
+ templatelist(Conf::xml_basedir + "/templates")
+{
+ for(int i = 0; i < Conf::database_poolsize; i++) {
+ dbpool.add(new Database(Conf::database_backend, Conf::database_addr,
+ "", Conf::database_user, Conf::database_passwd, ""));
+ }
+
+ for(int i = 0; i < Conf::artefact_poolsize; i++) {
+ atfpool.add(new Artefact);
+ }
+}
+
+Environment::~Environment()
+{
+ // Remove, but wait until resources are released
+ std::list<Database*> dblst = dbpool.clear(false);
+ std::list<Database*>::iterator i = dblst.begin();
+ while(i != dblst.end()) {
+ delete *i;
+ i++;
+ }
+
+ // Remove, but wait until resources are released
+ std::list<Artefact*> atflst = atfpool.clear(false);
+ std::list<Artefact*>::iterator j = atflst.begin();
+ while(j != atflst.end()) {
+ delete *j;
+ j++;
+ }
+}
+
+#ifdef TEST_ENVIRONMENT
+//deps: configuration.cc database.cc artefact.cc pracrodao.cc session.cc mutex.cc semaphore.cc debug.cc pracrodaotest.cc pracrodaopgsql.cc journalwriter.cc journal_commit.cc entitylist.cc inotify.cc exception.cc versionstr.cc tcpsocket.cc macrolist.cc templatelist.cc saxparser.cc log.cc macroheaderparser.cc templateheaderparser.cc
+//cflags: -DWITHOUT_ARTEFACT -I.. $(PQXX_CXXFLAGS) $(PTHREAD_CFLAGS) $(EXPAT_CFLAGS)
+//libs: $(PQXX_LIBS) -lpthread $(EXPAT_LIBS) $(PTHREAD_LIBS)
+#include "test.h"
+
+TEST_BEGIN;
+
+Conf::database_backend = "testdb";
+Conf::database_poolsize = 1;
+
+Conf::artefact_poolsize = 1;
+
+Conf::xml_basedir = "/tmp";
+
+TEST_NOEXCEPTION(Environment env, "Check if the Enviroment can be created.");
+
+TEST_END;
+
+#endif/*TEST_ENVIRONMENT*/
diff --git a/server/src/environment.h b/server/src/environment.h
new file mode 100644
index 0000000..a7b9677
--- /dev/null
+++ b/server/src/environment.h
@@ -0,0 +1,50 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set et sw=2 ts=2: */
+/***************************************************************************
+ * environment.h
+ *
+ * Tue Jan 5 11:41:23 CET 2010
+ * Copyright 2010 Bent Bisballe Nyeng
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of Pracro.
+ *
+ * Pracro 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 of the License, or
+ * (at your option) any later version.
+ *
+ * Pracro 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 Pracro; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#ifndef __PRACRO_ENVIRONMENT_H__
+#define __PRACRO_ENVIRONMENT_H__
+
+#include "database.h"
+#include "artefact.h"
+#include "connectionpool.h"
+#include "session.h"
+#include "templatelist.h"
+#include "macrolist.h"
+
+class Environment {
+public:
+ Environment();
+ ~Environment();
+
+ ConnectionPool<Database*> dbpool;
+ ConnectionPool<Artefact*> atfpool;
+ Sessions sessions;
+ MacroList macrolist;
+ TemplateList templatelist;
+};
+
+#endif/*__PRACRO_ENVIRONMENT_H__*/
diff --git a/server/src/inotify.cc b/server/src/inotify.cc
new file mode 100644
index 0000000..1515387
--- /dev/null
+++ b/server/src/inotify.cc
@@ -0,0 +1,549 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set et sw=2 ts=2: */
+/***************************************************************************
+ * inotify.cc
+ *
+ * Wed Jan 6 09:58:47 CET 2010
+ * Copyright 2010 Bent Bisballe Nyeng
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of Pracro.
+ *
+ * Pracro 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 of the License, or
+ * (at your option) any later version.
+ *
+ * Pracro 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 Pracro; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#include "inotify.h"
+
+#include "debug.h"
+
+#include <sys/stat.h>
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <dirent.h>
+#include <string.h>
+
+#define TEST(x, m) ((x & m) == m)
+
+#ifdef WITH_DEBUG
+#define STEST(x, m) (TEST(x, m)?#m" ":"")
+
+static std::string mask2asc(uint32_t mask)
+{
+ std::string str;
+
+ str += STEST(mask, IN_ACCESS);
+ str += STEST(mask, IN_ATTRIB);
+ str += STEST(mask, IN_CLOSE_WRITE);
+ str += STEST(mask, IN_CLOSE_NOWRITE);
+ str += STEST(mask, IN_CREATE);
+ str += STEST(mask, IN_DELETE);
+ str += STEST(mask, IN_DELETE_SELF);
+ str += STEST(mask, IN_MODIFY);
+ str += STEST(mask, IN_MOVE_SELF);
+ str += STEST(mask, IN_MOVED_FROM);
+ str += STEST(mask, IN_MOVED_TO);
+ str += STEST(mask, IN_OPEN);
+
+ str += STEST(mask, IN_ALL_EVENTS);
+ str += STEST(mask, IN_CLOSE);
+ str += STEST(mask, IN_MOVE);
+
+ str += STEST(mask, IN_DONT_FOLLOW);
+ str += STEST(mask, IN_MASK_ADD);
+ str += STEST(mask, IN_ONESHOT);
+ str += STEST(mask, IN_ONLYDIR);
+
+ str += STEST(mask, IN_IGNORED);
+ str += STEST(mask, IN_ISDIR);
+ str += STEST(mask, IN_Q_OVERFLOW);
+ str += STEST(mask, IN_UNMOUNT);
+
+ return str;
+}
+#endif
+
+static inline bool isdir(const char *name)
+{
+ struct stat s;
+ stat(name, &s);
+ return S_ISDIR(s.st_mode);
+}
+
+INotify::Event::Event(struct inotify_event *event, std::string name)
+{
+ this->_name = name;
+ if(event) {
+ this->_mask = event->mask;
+ this->_file = event->name;
+ } else {
+ this->_mask = 0;
+ this->_file = "";
+ }
+
+ PRACRO_DEBUG(inotify, "Event [%s] %s (%s)\n",
+ mask2asc(_mask).c_str(),
+ _name.c_str(),
+ _file.c_str());
+}
+
+bool INotify::Event::isAttributeChangeEvent()
+{
+ return TEST(_mask, IN_ATTRIB);
+}
+
+bool INotify::Event::isCloseEvent()
+{
+ return isCloseWriteEvent() || isCloseNoWriteEvent();
+}
+
+bool INotify::Event::isCloseWriteEvent()
+{
+ return TEST(_mask, IN_CLOSE_WRITE);
+}
+
+bool INotify::Event::isCloseNoWriteEvent()
+{
+ return TEST(_mask, IN_CLOSE_NOWRITE);
+}
+
+bool INotify::Event::isCreateEvent()
+{
+ return TEST(_mask, IN_CREATE);
+}
+
+bool INotify::Event::isOpenEvent()
+{
+ return TEST(_mask, IN_OPEN);
+}
+
+bool INotify::Event::isModifyEvent()
+{
+ return TEST(_mask, IN_MODIFY);
+}
+
+bool INotify::Event::isAccessEvent()
+{
+ return TEST(_mask, IN_ACCESS);
+}
+
+bool INotify::Event::isDeleteEvent()
+{
+ return TEST(_mask, IN_DELETE);
+}
+
+bool INotify::Event::isDeleteSelfEvent()
+{
+ return TEST(_mask, IN_DELETE_SELF);
+}
+
+bool INotify::Event::isIgnoredEvent()
+{
+ return TEST(_mask, IN_IGNORED);
+}
+
+bool INotify::Event::isMoveSelfEvent()
+{
+ return TEST(_mask, IN_MOVE_SELF);
+}
+
+bool INotify::Event::isMovedFromEvent()
+{
+ return TEST(_mask, IN_MOVED_FROM);
+}
+
+bool INotify::Event::isMovedToEvent()
+{
+ return TEST(_mask, IN_MOVED_TO);
+}
+
+bool INotify::Event::isDir()
+{
+ return TEST(_mask, IN_ISDIR);
+}
+
+std::string INotify::Event::name()
+{
+ return _name;
+}
+
+std::string INotify::Event::file()
+{
+ return _file;
+}
+
+uint32_t INotify::Event::mask()
+{
+ return _mask;
+}
+
+std::string INotify::Event::maskstr()
+{
+ return mask2asc(_mask);
+}
+
+INotify::INotify()
+{
+ ifd = inotify_init1(O_NONBLOCK);
+ if(ifd == -1) {
+ perror("Inotify init failed.\n");
+ return;
+ }
+}
+
+INotify::~INotify()
+{
+ if(ifd != -1) close(ifd);
+}
+
+void INotify::addFile(std::string name, uint32_t mask)
+{
+ // Extra mask bitflags:
+ //IN_DONT_FOLLOW (since Linux 2.6.15)
+ // Don't dereference pathname if it is a symbolic link.
+ //IN_MASK_ADD
+ // Add (OR) events to watch mask for this pathname if it already
+ // exists (instead of replacing mask).
+ //IN_ONESHOT
+ // Monitor pathname for one event, then remove from watch list.
+ //IN_ONLYDIR (since Linux 2.6.15)
+ // Only watch pathname if it is a directory.
+
+ int wd = inotify_add_watch(ifd, name.c_str(), mask);
+ if(wd == -1) {
+ perror("INotify: Add watch failed!");
+ return;
+ }
+
+ Watch w;
+ w.mask = mask;
+ w.name = name;
+ w.depth = WATCH_SINGLE;
+ dirmap[wd] = w;
+}
+
+static inline bool isdir(std::string name)
+{
+ struct stat s;
+ stat(name.c_str(), &s);
+ return S_ISDIR(s.st_mode);
+}
+
+void INotify::addDirectory(std::string name, depth_t depth, uint32_t mask)
+{
+ PRACRO_DEBUG(inotify, "Adding dir: %s\n", name.c_str());
+
+ int depth_mask = 0;
+ if(depth == WATCH_DEEP || depth == WATCH_DEEP_FOLLOW) {
+ depth_mask = IN_CREATE; // We need to watch for create in order to catch
+ // creation of new subdirs.
+
+ DIR *dir = opendir(name.c_str());
+ if(!dir) {
+ PRACRO_ERR(inotify, "Could not open directory: %s - %s\n",
+ name.c_str(), strerror(errno));
+ return;
+ }
+
+ struct dirent *dirent;
+ while( (dirent = readdir(dir)) != NULL ) {
+
+ if(std::string(dirent->d_name) == "." ||
+ std::string(dirent->d_name) == "..")
+ continue;
+
+ if(isdir(name+"/"+dirent->d_name))
+ addDirectory(name+"/"+dirent->d_name, depth, mask);
+ }
+
+ closedir(dir);
+ }
+
+ int wd = inotify_add_watch(ifd, name.c_str(), mask | IN_ONLYDIR | depth_mask);
+ if(wd == -1) {
+ PRACRO_ERR(inotify, "INotify: Add watch failed on %s\n", name.c_str());
+ return;
+ }
+
+ Watch w;
+ w.mask = mask;
+ w.name = name;
+ w.depth = depth;
+ dirmap[wd] = w;
+}
+
+void INotify::remove(int wd)
+{
+ if(inotify_rm_watch(ifd, wd) == -1) {
+ perror("inotify_rm_watch failed");
+ return;
+ }
+ dirmap.erase(wd);
+}
+
+void INotify::remove(std::string name)
+{
+ std::map<int, Watch>::iterator i = dirmap.begin();
+ while(i != dirmap.end()) {
+ Watch w = i->second;
+ if(w.name == name) this->remove(i->first);
+ i++;
+ }
+}
+
+void INotify::readEvents()
+{
+ size_t size = 64;
+ char *buf = (char*)malloc(size);
+
+ ssize_t r;
+ while( ((r = read(ifd, buf, size)) == -1 && errno == EINVAL) || r == 0 ) {
+ // fprintf(stderr, "Doubling buffer size: %d\n", size);
+ size *= 2;
+ buf = (char*)realloc(buf, size);
+ }
+
+ int p = 0;
+ while(p < r) {
+ struct inotify_event *event = (struct inotify_event*)(buf + p);
+ p += sizeof(struct inotify_event) + event->len;
+
+ /*
+ switch(event.mask) {
+ case IN_IGNORED:
+ //Watch was removed explicitly (inotify_rm_watch(2)) or automatically
+ // (file was deleted, or file system was unmounted).
+ case IN_ISDIR:
+ //Subject of this event is a directory.
+ case IN_Q_OVERFLOW:
+ //Event queue overflowed (wd is -1 for this event).
+ case IN_UNMOUNT:
+ //File system containing watched object was unmounted.
+ break;
+ default:
+ break;
+ }
+ */
+
+ // TODO: We need to figure out what the new filename/destination is...
+ if(TEST(event->mask, IN_MOVE_SELF)) dirmap[event->wd].name = "????????";
+
+ if(dirmap[event->wd].depth == WATCH_DEEP_FOLLOW &&
+ TEST(event->mask, IN_CREATE) &&
+ TEST(event->mask, IN_ISDIR))
+ addDirectory(dirmap[event->wd].name + "/" + event->name,
+ dirmap[event->wd].depth, dirmap[event->wd].mask);
+
+ if(TEST(event->mask, IN_CREATE) &&
+ !TEST(dirmap[event->wd].mask, IN_CREATE)) {
+ // Ignore this event, it was not requested by the user.
+ } else {
+ eventlist.push_back(INotify::Event(event, dirmap[event->wd].name));
+ }
+
+ if(TEST(event->mask, IN_IGNORED)) dirmap.erase(event->wd);
+ }
+
+ free(buf);
+}
+
+bool INotify::hasEvents()
+{
+ readEvents();
+ return eventlist.size() > 0;
+}
+
+INotify::Event INotify::getNextEvent()
+{
+ readEvents();
+ if(eventlist.size() == 0) return Event(NULL, "");
+ Event e = eventlist.front();
+ eventlist.pop_front();
+ return e;
+}
+
+void INotify::clear()
+{
+ if(ifd != -1) close(ifd);
+ ifd = inotify_init1(O_NONBLOCK);
+ if(ifd == -1) {
+ perror("Inotify init failed.\n");
+ }
+}
+
+#ifdef TEST_INOTIFY
+//deps: debug.cc
+//cflags: -I..
+//libs:
+#include "test.h"
+
+#include <stdio.h>
+
+#define _BASEDIR "/tmp"
+#define _DIR _BASEDIR"/inotify_test_dir"
+#define _FILE _BASEDIR"/inotify_test"
+
+TEST_BEGIN;
+
+pracro_debug_parse("+all");
+
+INotify inotify;
+
+// Create file
+FILE *fp = fopen(_FILE, "w");
+if(!fp) TEST_FATAL("Unable to write to the file");
+fprintf(fp, "something");
+fclose(fp);
+
+inotify.addFile(_FILE);
+
+TEST_MSG("Positive tests on file watch.");
+
+// Append to file
+fp = fopen(_FILE, "r");
+if(!fp) TEST_FATAL("Unable to read from the file");
+TEST_TRUE(inotify.hasEvents(), "Test if the open event was triggered.");
+TEST_TRUE(inotify.getNextEvent().isOpenEvent(), "Test if the event was an open event.");
+
+char buf[32];
+fread(buf, sizeof(buf), 1, fp);
+TEST_TRUE(inotify.hasEvents(), "Test if the read event was triggered.");
+TEST_TRUE(inotify.getNextEvent().isAccessEvent(), "Test if the event was a access event.");
+
+fclose(fp);
+TEST_TRUE(inotify.hasEvents(), "Test if the close event was triggered.");
+TEST_TRUE(inotify.getNextEvent().isCloseNoWriteEvent(), "Test if the event was a close-nowrite event.");
+
+
+// Append to file
+fp = fopen(_FILE, "a");
+if(!fp) TEST_FATAL("Unable to write to the file");
+TEST_TRUE(inotify.hasEvents(), "Test if the open event was triggered.");
+TEST_TRUE(inotify.getNextEvent().isOpenEvent(), "Test if the event was an open event.");
+
+fprintf(fp, "else"); fflush(fp);
+TEST_TRUE(inotify.hasEvents(), "Test if the append event was triggered.");
+TEST_TRUE(inotify.getNextEvent().isModifyEvent(), "Test if the event was a modified event.");
+
+fclose(fp);
+TEST_TRUE(inotify.hasEvents(), "Test if the close event was triggered.");
+TEST_TRUE(inotify.getNextEvent().isCloseWriteEvent(), "Test if the event was a close event.");
+
+
+// Overwrite file
+fp = fopen(_FILE, "w");
+if(!fp) TEST_FATAL("Unable to write to the file");
+
+// Open for write initially empties the file content, thus provoking a changed event.
+TEST_TRUE(inotify.hasEvents(), "Test if the modified event was triggered.");
+TEST_TRUE(inotify.getNextEvent().isModifyEvent(), "Test if the event was a modified event.");
+
+TEST_TRUE(inotify.hasEvents(), "Test if the open event was triggered.");
+TEST_TRUE(inotify.getNextEvent().isOpenEvent(), "Test if the event was an open event.");
+
+fprintf(fp, "else"); fflush(fp);
+TEST_TRUE(inotify.hasEvents(), "Test if the write event was triggered.");
+TEST_TRUE(inotify.getNextEvent().isModifyEvent(), "Test if the event was a modified event.");
+
+fclose(fp);
+TEST_TRUE(inotify.hasEvents(), "Test if the close event was triggered.");
+TEST_TRUE(inotify.getNextEvent().isCloseWriteEvent(), "Test if the event was a close event.");
+
+// Rename file
+rename(_FILE, _FILE"2");
+TEST_TRUE(inotify.hasEvents(), "Test if the rename event was triggered.");
+TEST_TRUE(inotify.getNextEvent().isMoveSelfEvent(), "Test if the event was a move self event.");
+
+// Delete file
+unlink(_FILE"2");
+
+// Unlink initially counts down the link counter, which provokes an attributes changed event.
+TEST_TRUE(inotify.hasEvents(), "Test if the delete event was triggered.");
+TEST_TRUE(inotify.getNextEvent().isAttributeChangeEvent(), "Test if the event was an attribute change event.");
+
+// Since the linkcount should now be zero, the file should be deleted.
+TEST_TRUE(inotify.hasEvents(), "Test if the delete event was triggered.");
+TEST_TRUE(inotify.getNextEvent().isDeleteSelfEvent(), "Test if the event was a delete self event.");
+
+// Watch is removed upon delete.
+//inotify.remove(_FILE);
+
+TEST_TRUE(inotify.hasEvents(), "Test if the delete event triggered an ignored event.");
+TEST_TRUE(inotify.getNextEvent().isIgnoredEvent(), "Test if the event was an ignored event.");
+
+// Create file again
+fp = fopen(_FILE, "w");
+if(!fp) TEST_FATAL("Unable to write to the file");
+fprintf(fp, "something");
+fclose(fp);
+
+inotify.addFile(_FILE);
+inotify.remove(_FILE);
+
+TEST_TRUE(inotify.hasEvents(), "Test if the call to remove triggered an ignored event.");
+TEST_TRUE(inotify.getNextEvent().isIgnoredEvent(), "Test if the event was an ignored event.");
+
+// Delete file
+unlink(_FILE);
+inotify.getNextEvent();
+TEST_FALSE(inotify.hasEvents(), "Test if the delete event was ignored.");
+
+TEST_FALSE(inotify.hasEvents(), "Test if the event queue is now empty.");
+
+TEST_MSG("Positive tests on directory watch.");
+
+if(mkdir(_DIR, 0777) == -1) TEST_FATAL("Could not create test dir.");
+inotify.addDirectory(_DIR, WATCH_DEEP_FOLLOW);
+
+// Create file again
+fp = fopen(_DIR"/file1", "w");
+if(!fp) TEST_FATAL("Unable to write to the file");
+fprintf(fp, "something");
+fclose(fp);
+
+TEST_TRUE(inotify.hasEvents(), "Test if the file creation triggered events.");
+TEST_TRUE(inotify.getNextEvent().isCreateEvent(), "...");
+TEST_TRUE(inotify.getNextEvent().isOpenEvent(), "...");
+TEST_TRUE(inotify.getNextEvent().isModifyEvent(), "...");
+TEST_TRUE(inotify.getNextEvent().isCloseWriteEvent(), "...");
+
+rename(_DIR"/file1", _DIR"/file2");
+TEST_TRUE(inotify.hasEvents(), "Test if the file renaming triggered events.");
+TEST_TRUE(inotify.getNextEvent().isMovedFromEvent(), "...");
+TEST_TRUE(inotify.getNextEvent().isMovedToEvent(), "...");
+
+unlink(_DIR"/file2");
+
+if(mkdir(_DIR"/dir", 0777) == -1) TEST_FATAL("Could not create test dir.");
+
+if(mkdir(_DIR"/dir/anotherdir", 0777) == -1) TEST_FATAL("Could not create test dir.");
+
+while(inotify.hasEvents()) inotify.getNextEvent();
+
+rmdir(_DIR"/dir/anotherdir");
+
+rmdir(_DIR"/dir");
+
+rmdir(_DIR);
+
+while(inotify.hasEvents()) inotify.getNextEvent();
+
+TEST_END;
+
+#endif/*TEST_INOTIFY*/
diff --git a/server/src/inotify.h b/server/src/inotify.h
new file mode 100644
index 0000000..d63e384
--- /dev/null
+++ b/server/src/inotify.h
@@ -0,0 +1,118 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set et sw=2 ts=2: */
+/***************************************************************************
+ * inotify.h
+ *
+ * Wed Jan 6 09:58:47 CET 2010
+ * Copyright 2010 Bent Bisballe Nyeng
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of Pracro.
+ *
+ * Pracro 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 of the License, or
+ * (at your option) any later version.
+ *
+ * Pracro 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 Pracro; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#ifndef __PRACRO_INOTIFY_H__
+#define __PRACRO_INOTIFY_H__
+
+#include <sys/types.h>
+#include <sys/inotify.h>
+
+#include <string>
+#include <map>
+#include <list>
+
+typedef enum {
+ WATCH_SINGLE, // Watch only the specified directory.
+ WATCH_DEEP, // Watch all current subdirs as well
+ WATCH_DEEP_FOLLOW // Watch all current subdir as well as subdirs
+ // being created after the watch is initiated
+} depth_t;
+
+
+class INotify {
+public:
+ class Event {
+ public:
+ Event(struct inotify_event *event, std::string name);
+
+ bool isAttributeChangeEvent();
+ bool isCreateEvent();
+ bool isOpenEvent();
+ bool isCloseEvent();
+ bool isCloseWriteEvent();
+ bool isCloseNoWriteEvent();
+ bool isModifyEvent();
+ bool isAccessEvent();
+ bool isDeleteEvent();
+ bool isDeleteSelfEvent();
+ bool isIgnoredEvent();
+ bool isMoveSelfEvent();
+ bool isMovedFromEvent();
+ bool isMovedToEvent();
+
+ bool isDir();
+
+ std::string name();
+ std::string file();
+ uint32_t mask();
+ std::string maskstr();
+
+ private:
+ std::string _name;
+ std::string _file;
+ uint32_t _mask;
+ };
+
+ INotify();
+ ~INotify();
+
+ void addFile(std::string name, uint32_t mask = IN_ALL_EVENTS);
+
+ /**
+ * WARNING: If a directory is added with WATCH_DEEP_FOLLOW, newly
+ * created folders will not be added to the watch before the next call
+ * to hasEvents or getNextEvent. thie means that any files created in
+ * that folder prior to htese calls will not be caught. This will need
+ * to be done mnually by a recursive scan.
+ */
+ void addDirectory(std::string name,
+ depth_t depth = WATCH_SINGLE,
+ uint32_t mask = IN_ALL_EVENTS);
+ void remove(std::string name);
+ void remove(int fd);
+
+ bool hasEvents();
+ Event getNextEvent();
+
+ void clear();
+
+private:
+ class Watch {
+ public:
+ std::string name;
+ uint32_t mask;
+ depth_t depth;
+ };
+
+ void readEvents();
+
+ int ifd;
+ std::map<int, Watch> dirmap;
+ std::list<Event> eventlist;
+};
+
+#endif/*__PRACRO_INOTIFY_H__*/
diff --git a/server/src/journal_commit.cc b/server/src/journal_commit.cc
index a94f1d4..56e7baf 100644
--- a/server/src/journal_commit.cc
+++ b/server/src/journal_commit.cc
@@ -51,8 +51,8 @@
#include "template.h"
#include "templateparser.h"
-#include "xml_encode_decode.h"
+#if 0
static inline bool iswhitespace(char c)
{
return c == ' ' || c == '\n' || c == '\t';
@@ -110,6 +110,7 @@ static std::string addNewlines(std::string str, size_t width)
return output;
}
+#endif
static int mwrite(int sock, const char *fmt, ...)
{
@@ -201,103 +202,10 @@ int journal_commit(const char *cpr, const char *user,
return 0;
}
-JournalWriter::JournalWriter(std::string host, unsigned short int port)
-{
- this->host = host;
- this->port = port;
-}
-
-void JournalWriter::addEntry(Transaction &transaction, Commit &commit,
- std::string resume, Template *templ)
-{
- size_t index = 0;
- std::vector< Macro >::iterator i = templ->macros.begin();
- while(i != templ->macros.end()) {
- Macro &m = *i;
- if(commit.macro == m.attributes["name"]) break;
- index++;
- i++;
- }
-
- if(index >= templ->macros.size()) {
- PRACRO_ERR(journal, "Could not find macro %s in template %s\n",
- commit.macro.c_str(), templ->attributes["name"].c_str());
- // return;
- } else {
- PRACRO_DEBUG(journal, "Found macro %s as index %u in template %s\n",
- commit.macro.c_str(), index, templ->attributes["name"].c_str());
- }
-
- // First run - initialize username and cpr.
- if(currentuser == "" && entrylist.size() == 0) currentuser = transaction.user;
- if(currentcpr == "" && entrylist.size() == 0) currentcpr = transaction.cpr;
-
- PRACRO_DEBUG(journal, "addEntry: template(%s)\n", templ->attributes["name"].c_str());
-
- // Add the template resume as the header (ie. first entry) of the journal entry.
- if(entrylist.size() == 0 && templ->attributes["name"] != "") {
- std::string template_resume = templ->attributes["resume"];
-
- PRACRO_DEBUG(journal, "TemplateResume: %s\n", template_resume.c_str());
-
- if(template_resume != "") {
- ResumeEntry re;
- re.resume = template_resume;
- re.macro = "template_header";
- entrylist[-1] = re; // Make sure it comes first.
- }
- }
-
- // Test if the username or the cpr has changed... if so, commit and clear the list.
- if(currentuser != transaction.user || currentcpr != transaction.cpr) {
- this->commit();
- entrylist.clear();
- }
-
- // Strip trailing whitespace, and add newlines.
- std::string r = stripTrailingWhitepace(addNewlines(xml_decode(resume), 60));
- std::string m = commit.macro;
-
- ResumeEntry re;
- re.resume = r;
- re.macro = m;
- entrylist[index] = re;
-}
-
-void JournalWriter::commit()
-{
- std::string resume;
-
- // Iterate through all resumes, and create a string containing them all.
- std::map< int, ResumeEntry >::iterator i = entrylist.begin();
- while(i != entrylist.end()) {
- if(resume != "") resume += "\n\n";
- // resume += i->macro + "\n";
- resume += i->second.resume;
- i++;
- }
-
- if(resume == "") return;
-
- // Connect to praxisuploadserver and commit all resumes in one bulk.
- journal_commit(currentcpr.c_str(), currentuser.c_str(),
- host.c_str(), port,
- resume.c_str(), resume.size());
-}
-
-
#ifdef TEST_JOURNAL_COMMIT
int main()
{
- std::string text = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do\neiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. \n\n \t";
-
- std::string resume = stripTrailingWhitepace(addNewlines(text, 60));
- printf("[%s]\n", resume.c_str());
-
- resume = stripTrailingWhitepace(addNewlines("", 60));
- printf("[%s]\n", resume.c_str());
-
return 0;
}
diff --git a/server/src/journal_commit.h b/server/src/journal_commit.h
index 4f7f211..1bc8086 100644
--- a/server/src/journal_commit.h
+++ b/server/src/journal_commit.h
@@ -27,35 +27,10 @@
#ifndef __PRACRO_JOURNAL_COMMIT_H__
#define __PRACRO_JOURNAL_COMMIT_H__
-#include <string>
-#include <map>
+#include <unistd.h>
-#include "transaction.h"
-#include "template.h"
-
-class JournalWriter {
-public:
- JournalWriter(std::string host, unsigned short int port);
-
- void addEntry(Transaction &transaction, Commit &commit,
- std::string resume, Template *templ);
-
- void commit();
-
-private:
- std::string host;
- unsigned short int port;
-
- std::string currentuser;
- std::string currentcpr;
-
- class ResumeEntry {
- public:
- std::string resume;
- std::string macro;
- };
-
- std::map< int, ResumeEntry > entrylist;
-};
+int journal_commit(const char *cpr, const char *user,
+ const char *addr, unsigned short int port,
+ const char *buf, size_t size);
#endif/*__PRACRO_JOURNAL_COMMIT_H__*/
diff --git a/server/src/journalwriter.cc b/server/src/journalwriter.cc
new file mode 100644
index 0000000..4b2b4be
--- /dev/null
+++ b/server/src/journalwriter.cc
@@ -0,0 +1,350 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; coding: utf-8 -*- */
+/* vim: set et sw=2 ts=2: */
+/***************************************************************************
+ * journalwriter.cc
+ *
+ * Tue Jan 5 15:52:54 CET 2010
+ * Copyright 2010 Bent Bisballe Nyeng
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of Pracro.
+ *
+ * Pracro 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 of the License, or
+ * (at your option) any later version.
+ *
+ * Pracro 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 Pracro; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#include "journalwriter.h"
+
+#include "debug.h"
+#include "journal_commit.h"
+
+static inline bool iswhitespace(char c)
+{
+ return c == ' ' || c == '\n' || c == '\t' || c == '\r';
+}
+
+/**
+ * Remove all spaces, tabs and newline trailing the string.
+ */
+static std::string stripTrailingWhitepace(const std::string &str)
+{
+ if(str == "") return str;
+
+ ssize_t end = str.size() - 1;
+
+ while(end >= 0 && iswhitespace(str[end])) end--;
+ end++;
+
+ return str.substr(0, end);
+}
+
+static bool isInsideUTF8(const std::string &str, size_t idx)
+{
+ // Two byte character
+ if(idx > 0 &&
+ (str[idx] & 0xC0 ) == 0x80 &&
+ (str[idx - 1] & 0xE0) == 0xC0)
+ return true;
+
+ // Three byte character
+ if(idx > 1 &&
+ (str[idx] & 0xC0 ) == 0x80 &&
+ (str[idx - 1] & 0xC0 ) == 0x80 &&
+ (str[idx - 2] & 0xF0) == 0xE0)
+ return true;
+
+ if(idx > 0 &&
+ (str[idx] & 0xC0 ) == 0x80 &&
+ (str[idx - 1] & 0xF0) == 0xE0)
+ return true;
+
+ // Four byte character
+ if(idx > 2 &&
+ (str[idx] & 0xC0 ) == 0x80 &&
+ (str[idx - 1] & 0xC0 ) == 0x80 &&
+ (str[idx - 2] & 0xC0 ) == 0x80 &&
+ (str[idx - 3] & 0xF8) == 0xF0)
+ return true;
+
+ if(idx > 1 &&
+ (str[idx] & 0xC0 ) == 0x80 &&
+ (str[idx - 1] & 0xC0 ) == 0x80 &&
+ (str[idx - 2] & 0xF8) == 0xF0)
+ return true;
+
+ if(idx > 0 &&
+ (str[idx] & 0xC0 ) == 0x80 &&
+ (str[idx - 1] & 0xF8) == 0xF0)
+ return true;
+
+ return false;
+}
+
+static size_t UTF8Length(const std::string &str)
+{
+ size_t size = 0;
+ for(size_t i = 0; i < str.size(); i++) {
+ if(!isInsideUTF8(str, i)) size++;
+ }
+ return size;
+}
+
+/**
+ * Find all lines longer than 'width', and insert a newline in the
+ * first backward occurring space. Force split any lines without a space.
+ */
+static std::string addNewlines(const std::string &str, size_t width)
+{
+ std::string output;
+ size_t len = 0;
+ for(size_t i = 0; i < str.size(); i++) {
+ char c = str[i];
+
+ /*
+ fprintf(stderr, "i: %d, char: '%c', width: %d, len: %d, output: '%s'\n",
+ i, c, width, len, output.c_str());
+ */
+
+ output += c;
+
+ if(isInsideUTF8(str, i)) continue;
+
+ len++;
+ if(c == '\n') len = 0;
+
+ // Try to split line at whitespace.
+ if(len > width) {
+ size_t p = 0;
+ while(p < width) {
+ p++;
+
+ size_t pos = output.size() - p;
+
+ if(isInsideUTF8(output, pos)) continue;
+
+ if(iswhitespace(output[pos])) {
+ output[pos] = '\n';
+ len = UTF8Length(output.substr(pos+1));
+ break;
+ }
+ }
+ }
+
+ // Force split line at current pos.
+ if(len > width) {
+ // replace last char with a newline, and append the character again, after the newline.
+ output[output.size()-1] = '\n';
+ output += c;
+ len = 1;
+ }
+ }
+
+ return output;
+}
+
+JournalWriter::JournalWriter(std::string host, unsigned short int port)
+{
+ this->host = host;
+ this->port = port;
+}
+
+void JournalWriter::addEntry(Transaction &transaction, Commit &commit,
+ std::string resume, Template *templ)
+{
+ size_t index = 0;
+ std::vector< Macro >::iterator i = templ->macros.begin();
+ while(i != templ->macros.end()) {
+ Macro &m = *i;
+ if(commit.macro == m.attributes["name"]) break;
+ index++;
+ i++;
+ }
+
+ if(index >= templ->macros.size()) {
+ PRACRO_ERR(journal, "Could not find macro %s in template %s\n",
+ commit.macro.c_str(), templ->attributes["name"].c_str());
+ // return;
+ } else {
+ PRACRO_DEBUG(journal, "Found macro %s as index %u in template %s\n",
+ commit.macro.c_str(), index, templ->attributes["name"].c_str());
+ }
+
+ // First run - initialize username and cpr.
+ if(currentuser == "" && entrylist.size() == 0) currentuser = transaction.user;
+ if(currentcpr == "" && entrylist.size() == 0) currentcpr = transaction.cpr;
+
+ PRACRO_DEBUG(journal, "addEntry: template(%s)\n", templ->attributes["name"].c_str());
+
+#if 0 // this feature is no longer nessecary...
+ // Add the template resume as the header (ie. first entry)
+ // of the journal entry.
+ if(entrylist.size() == 0 && templ->attributes["name"] != "") {
+ std::string template_resume = templ->attributes["resume"];
+
+ PRACRO_DEBUG(journal, "TemplateResume: %s\n", template_resume.c_str());
+
+ if(template_resume != "") {
+ ResumeEntry re;
+ re.resume = template_resume;
+ re.macro = "template_header";
+ entrylist[-1] = re; // Make sure it comes first.
+ }
+ }
+#endif
+
+ // Test if the username or the cpr has changed...
+ // if so, commit and clear the list.
+ if(currentuser != transaction.user || currentcpr != transaction.cpr) {
+ this->commit();
+ entrylist.clear();
+ }
+
+ addEntry(resume, commit.macro, index);
+}
+
+void JournalWriter::addEntry(std::string resume, std::string macro, int index)
+{
+ // Strip trailing whitespace, and add newlines.
+ std::string r = stripTrailingWhitepace(addNewlines(resume, 60));
+ std::string m = macro;
+
+ ResumeEntry re;
+ re.resume = r;
+ re.macro = m;
+ entrylist[index] = re;
+}
+
+void JournalWriter::commit()
+{
+ std::string resume;
+
+ // Iterate through all resumes, and create a string containing them all.
+ std::map< int, ResumeEntry >::iterator i = entrylist.begin();
+ while(i != entrylist.end()) {
+ if(resume != "") resume += "\n\n";
+ // resume += i->macro + "\n";
+ resume += i->second.resume;
+ i++;
+ }
+
+ if(resume == "") return;
+
+ // Connect to praxisuploadserver and commit all resumes in one bulk.
+ journal_commit(currentcpr.c_str(), currentuser.c_str(),
+ host.c_str(), port,
+ resume.c_str(), resume.size());
+}
+
+#ifdef TEST_JOURNALWRITER
+//deps: debug.cc journal_commit.cc
+//cflags: -I..
+//libs:
+#include "test.h"
+
+#define LONG "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do\neiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. \n\n \t";
+
+TEST_BEGIN;
+
+TEST_EQUAL_STR(stripTrailingWhitepace
+ ("Lorem ipsum dolor sit amet. \n\n \t"),
+ "Lorem ipsum dolor sit amet.", "Test wspace remover.");
+
+TEST_EQUAL_STR(stripTrailingWhitepace(""), "", "Test wspace remover on empty string.");
+
+TEST_EQUAL_STR(stripTrailingWhitepace("\n\t "), "", "Test wspace remover on wspace-only string.");
+
+TEST_EQUAL_STR(stripTrailingWhitepace("\n"), "", "Test wspace remover on newline only.");
+TEST_EQUAL_STR(stripTrailingWhitepace("\t"), "", "Test wspace remover on tab only.");
+TEST_EQUAL_STR(stripTrailingWhitepace("\r"), "", "Test wspace remover on space only.");
+TEST_EQUAL_STR(stripTrailingWhitepace(" "), "", "Test wspace remover on space only.");
+
+TEST_EQUAL_STR(stripTrailingWhitepace("ø "), "ø", "Test wspace remover on utf-8 char.");
+TEST_EQUAL_STR(stripTrailingWhitepace("ø"), "ø", "Test wspace remover on utf-8 char only.");
+
+TEST_EQUAL_STR(stripTrailingWhitepace("a "), "a", "Test wspace remover on single char only.");
+TEST_EQUAL_STR(stripTrailingWhitepace("a"), "a", "Test wspace remover on single char only.");
+
+TEST_EQUAL_STR(addNewlines
+ ("Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do.", 60),
+ "Lorem ipsum dolor sit amet, consectetur adipisicing elit,\nsed do.",
+ "Test single linesplit.");
+
+TEST_EQUAL_STR(addNewlines
+ ("Lorem ipsum dolor sit amet, consectetur adipisicing elit, øsed do.", 60),
+ "Lorem ipsum dolor sit amet, consectetur adipisicing elit,\nøsed do.",
+ "Test single linesplit around utf-8 char.");
+
+TEST_EQUAL_STR(addNewlines
+ ("Lorem ipsum dolor sit amet, consectetur adipisicing elitø, sed do.", 60),
+ "Lorem ipsum dolor sit amet, consectetur adipisicing elitø,\nsed do.",
+ "Test single linesplit around utf-8 char.");
+
+TEST_EQUAL_STR(addNewlines
+ ("Lorem\nipsum dolor sit amet.", 12),
+ "Lorem\nipsum dolor\nsit amet.",
+ "Test single linesplit with contained newline.");
+
+TEST_EQUAL_STR(addNewlines
+ ("Lorem ipsum dolor sitan met.", 11),
+ "Lorem ipsum\ndolor sitan\nmet.",
+ "Test single linesplit on exact border.");
+
+TEST_EQUAL_STR(addNewlines
+ ("Loremipsum", 6),
+ "Loremi\npsum",
+ "Test single linesplit inside word.");
+
+TEST_EQUAL_STR(addNewlines
+ ("abc Loremipsum", 6),
+ "abc\nLoremi\npsum",
+ "Test single linesplit inside word.");
+
+TEST_TRUE(isInsideUTF8("ø", 1), "Test positive utf8 match.");
+TEST_TRUE(isInsideUTF8("aæb", 2), "Test positive utf8 match.");
+TEST_TRUE(isInsideUTF8("aøb", 2), "Test positive utf8 match.");
+TEST_TRUE(isInsideUTF8("aåb", 2), "Test positive utf8 match.");
+TEST_TRUE(isInsideUTF8("aÆb", 2), "Test positive utf8 match.");
+TEST_TRUE(isInsideUTF8("aØb", 2), "Test positive utf8 match.");
+TEST_TRUE(isInsideUTF8("aÃ…b", 2), "Test positive utf8 match.");
+TEST_FALSE(isInsideUTF8("ø", 0), "Test negative utf8 match.");
+TEST_FALSE(isInsideUTF8("aæøb", 3), "Test negative utf8 match (between two utf8 chars).");
+TEST_FALSE(isInsideUTF8("aøb", 0), "Test negative utf8 match (before utf8 char).");
+
+TEST_FALSE(isInsideUTF8("𤭢", 0), "Test positive utf8 match, len 4.");
+TEST_TRUE(isInsideUTF8("𤭢", 1), "Test positive utf8 match, len 4.");
+TEST_TRUE(isInsideUTF8("𤭢", 2), "Test positive utf8 match, len 4.");
+TEST_TRUE(isInsideUTF8("𤭢", 3), "Test positive utf8 match, len 4.");
+
+TEST_FALSE(isInsideUTF8("€", 0), "Test positive utf8 match, len 3.");
+TEST_TRUE(isInsideUTF8("€", 1), "Test positive utf8 match, len 3.");
+TEST_TRUE(isInsideUTF8("€", 2), "Test positive utf8 match, len 3.");
+
+TEST_FALSE(isInsideUTF8("¢", 0), "Test positive utf8 match, len 2.");
+TEST_TRUE(isInsideUTF8("¢", 1), "Test positive utf8 match, len 2.");
+
+TEST_EQUAL_INT(UTF8Length("ø"), 1, "Test utf8 string length.");
+TEST_EQUAL_INT(UTF8Length("æø"), 2, "Test utf8 string length.");
+TEST_EQUAL_INT(UTF8Length(""), 0, "Test utf8 string length.");
+TEST_EQUAL_INT(UTF8Length("a"), 1, "Test utf8 string length.");
+TEST_EQUAL_INT(UTF8Length("aø"), 2, "Test utf8 string length.");
+TEST_EQUAL_INT(UTF8Length("aøb"), 3, "Test utf8 string length.");
+
+TEST_EQUAL_INT(UTF8Length("a𤭢€¢ø𤭢€¢øa"), 10, "Test utf8 string length, combi.");
+
+TEST_EQUAL_STR(stripTrailingWhitepace(addNewlines("", 60)), "", "Test on empty input.");
+
+TEST_END;
+
+#endif/*TEST_JOURNALWRITER*/
diff --git a/server/src/journalwriter.h b/server/src/journalwriter.h
new file mode 100644
index 0000000..2cd191d
--- /dev/null
+++ b/server/src/journalwriter.h
@@ -0,0 +1,67 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set et sw=2 ts=2: */
+/***************************************************************************
+ * journalwriter.h
+ *
+ * Tue Jan 5 15:52:54 CET 2010
+ * Copyright 2010 Bent Bisballe Nyeng
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of Pracro.
+ *
+ * Pracro 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 of the License, or
+ * (at your option) any later version.
+ *
+ * Pracro 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 Pracro; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#ifndef __PRACRO_JOURNALWRITER_H__
+#define __PRACRO_JOURNALWRITER_H__
+
+#include <string>
+#include <map>
+
+#include "transaction.h"
+#include "template.h"
+
+class SessionSerialiser;
+
+class JournalWriter {
+ friend class SessionSerialiser;
+public:
+ JournalWriter(std::string host, unsigned short int port);
+
+ void addEntry(Transaction &transaction, Commit &commit,
+ std::string resume, Template *templ);
+
+ void addEntry(std::string resume, std::string macro, int index);
+
+ void commit();
+
+private:
+ std::string host;
+ unsigned short int port;
+
+ std::string currentuser;
+ std::string currentcpr;
+
+ class ResumeEntry {
+ public:
+ std::string resume;
+ std::string macro;
+ };
+
+ std::map< int, ResumeEntry > entrylist;
+};
+
+#endif/*__PRACRO_JOURNALWRITER_H__*/
diff --git a/server/src/luaresume.cc b/server/src/luaresume.cc
index b7e7348..099c3bd 100644
--- a/server/src/luaresume.cc
+++ b/server/src/luaresume.cc
@@ -26,6 +26,8 @@
*/
#include "luaresume.h"
+#include "luautil.h"
+
#include "debug.h"
#include <stdio.h>
@@ -34,14 +36,9 @@
static int _getValue(lua_State *L)
{
- int n = lua_gettop(L); // number of arguments
- if(n != 1) {
- char errstr[512];
- sprintf(errstr, "Number of args expected 0, got %d", n);
- lua_pushstring(L, errstr);
- lua_error(L);
- return 1;
- }
+ Pracro::checkParameters(L,
+ Pracro::T_STRING,
+ Pracro::T_END);
std::string name = lua_tostring(L, lua_gettop(L));
@@ -65,7 +62,7 @@ LUAResume::LUAResume(Commit &c)
{
L = luaL_newstate();
if(L == NULL) {
- error("Could not create LUA state.");
+ PRACRO_ERR(luaresume, "Could not create LUA state.\n");
return;
}
@@ -85,7 +82,7 @@ LUAResume::~LUAResume()
std::string LUAResume::getValue(std::string name)
{
if(commit.fields.find(name) == commit.fields.end()) {
- error("LUAResume: No such field '" + name + "'");
+ PRACRO_ERR(luaresume, "LUAResume: No such field '%s'\n", name.c_str());
return "";
}
@@ -95,7 +92,7 @@ std::string LUAResume::getValue(std::string name)
std::string LUAResume::run(std::string program)
{
if(L == NULL) {
- error("LUA state not initialized!");
+ PRACRO_ERR(luaresume, "LUA state not initialized!");
return false;
}
@@ -111,24 +108,25 @@ std::string LUAResume::run(std::string program)
int top = lua_gettop(L);
- if(luaL_loadbuffer(L, program.c_str(), program.size(), "lua resume generator")) {
- error(lua_tostring(L, lua_gettop(L)));
+ if(luaL_loadbuffer(L, program.c_str(), program.size(),
+ "lua resume generator")) {
+ PRACRO_ERR(luaresume, "loadbufer: %s\n", lua_tostring(L, lua_gettop(L)));
return false;
}
// Run the loaded code
if(lua_pcall(L, 0, LUA_MULTRET, 0)) {
- error(lua_tostring(L, lua_gettop(L)));
+ PRACRO_ERR(luaresume, "pcall: %s\n" , lua_tostring(L, lua_gettop(L)));
return false;
}
if(top != lua_gettop(L) - 1) {
- error("Program did not return a single value.\n");
+ PRACRO_ERR(luaresume, "Program did not return a single value.\n");
return false;
}
if(lua_isstring(L, lua_gettop(L)) == false) {
- error("Program did not return a string value.\n");
+ PRACRO_ERR(luaresume, "Program did not return a string value.\n");
return false;
}
diff --git a/server/src/luautil.cc b/server/src/luautil.cc
new file mode 100644
index 0000000..116d219
--- /dev/null
+++ b/server/src/luautil.cc
@@ -0,0 +1,312 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * luautil.cc
+ *
+ * Fri Apr 13 14:38:53 CEST 2007
+ * Copyright 2007 Bent Bisballe Nyeng
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of Pracro.
+ *
+ * Pracro 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 of the License, or
+ * (at your option) any later version.
+ *
+ * Pracro 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 Pracro; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#include "luautil.h"
+
+#include "debug.h"
+
+#include <string>
+
+#include <vector>
+
+std::vector< void * > pointers;
+
+// for ntohl and htonl
+#include <arpa/inet.h>
+
+#define GLOBAL_PREFIX "magic_global_"
+
+//
+// Get the (somewhat hacky) global pointer to the parser object.
+// It is set in the preload method.
+//
+void *Pracro::getGlobal(lua_State *L, std::string name)
+{
+ unsigned int top;
+ unsigned int index;
+
+ std::string var = std::string(GLOBAL_PREFIX) + name;
+
+ lua_getfield(L, LUA_GLOBALSINDEX, var.c_str());
+ top = lua_gettop(L);
+ index = lua_tointeger(L, top);
+
+ return pointers.at(index);
+}
+
+void Pracro::setGlobal(lua_State *L, std::string name, void *p)
+{
+ // Put the value of this in the globals
+ char value_of_this[256];
+
+ std::string val = std::string(GLOBAL_PREFIX) + name;
+
+ /*
+ unsigned int parser = (unsigned int)p;
+ parser = htonl(parser);
+ */
+
+ pointers.push_back(p);
+ unsigned int index = pointers.size() - 1;
+
+ sprintf(value_of_this, "%s = %u\n", val.c_str(), index);
+ int s = luaL_loadstring(L, value_of_this);
+ switch(s) {
+ case 0: //no errors;
+ break;
+ case LUA_ERRSYNTAX: //syntax error during pre-compilation;
+ case LUA_ERRMEM: //memory allocation error.
+ fprintf(stderr, "Error: %s\n", lua_tostring(L, lua_gettop(L)));
+ default:
+ fprintf(stderr, "Unknown return value of luaL_loadstring.\n");
+ }
+
+ // Run program (init)
+ s = lua_pcall(L, 0, LUA_MULTRET, 0);
+ // Check for errors
+ switch(s) {
+ case 0: // Success
+ break;
+ case LUA_ERRRUN:// a runtime error.
+ case LUA_ERRMEM:// memory allocation error.
+ // For such errors, Lua does not call the error handler function.
+ case LUA_ERRERR:// error while running the error handler function.
+ fprintf(stderr, "Error: %s\n", lua_tostring(L, lua_gettop(L)));
+ break;
+ default:
+ fprintf(stderr, "Error: Unknown return value of lua_pcall.\n");
+ break;
+ }
+}
+
+void Pracro::call(lua_State *L, std::string function, int numargs)
+{
+ // Get function
+ lua_getglobal(L, function.c_str());
+
+ // Call it
+ int s = lua_pcall(L, numargs, LUA_MULTRET, 0);
+
+ // Check for errors
+ switch(s) {
+ case 0: // Success
+ break;
+ case LUA_ERRRUN:// a runtime error.
+ case LUA_ERRMEM:// memory allocation error.
+ // For such errors, Lua does not call the error handler function.
+ case LUA_ERRERR:// error while running the error handler function.
+ fprintf(stderr, "Error: %s\n", lua_tostring(L, lua_gettop(L)));
+ break;
+ default:
+ fprintf(stderr, "Error: Unknown return value of lua_pcall.\n");
+ break;
+ }
+}
+
+
+/*
+lua_isboolean
+lua_iscfunction
+lua_isfunction
+lua_islightuserdata
+lua_isnil
+lua_isnone
+lua_isnoneornil
+lua_isnumber
+lua_isstring
+lua_istable
+lua_isthread
+lua_isuserdata
+*/
+int Pracro::checkParameters(lua_State *L, ...)
+{
+ va_list ap;
+ va_start(ap, L);
+
+ size_t nargs = lua_gettop(L); // number of arguments
+
+ size_t size = 0;
+ int t;
+ while(1) {
+ t = va_arg(ap, int);
+ if(t == T_END) break;
+
+ switch(t) {
+ case T_STRING:
+ case T_NUMBER:
+ case T_BOOLEAN:
+ break;
+
+ default:
+ return luaL_error(L,"Unknown type specifier [%d] at position %d. "
+ "Missing TYPE_END?", t, size+1);
+ }
+
+ size++;
+ }
+
+ va_end(ap);
+
+ if(nargs != size) {
+ return luaL_error(L, "Number of args expected %d, got %d", size, nargs);
+ }
+
+ va_start(ap, L);
+
+ size_t idx = 0;
+ while(1) {
+ t = va_arg(ap, int);
+ if(t == T_END) break;
+
+ switch(t) {
+ case T_STRING:
+ if(lua_isstring(L, lua_gettop(L)-(size-idx-1)) == 0) {
+ va_end(ap);
+ return luaL_error(L, "Parameter %d should be of type string.", idx+1);
+ }
+ break;
+
+ case T_NUMBER:
+ if(lua_isnumber(L, lua_gettop(L)-(size-idx-1)) == 0) {
+ va_end(ap);
+ return luaL_error(L, "Parameter %d should be of type number.", idx+1);
+ }
+ break;
+
+ case T_BOOLEAN:
+ if(lua_isboolean(L, lua_gettop(L)-(size-idx-1)) == 0) {
+ va_end(ap);
+ return luaL_error(L, "Parameter %d should be of type boolean.", idx+1);
+ }
+ break;
+
+ default:
+ va_end(ap);
+ return luaL_error(L,"Unknown type specifier [%d] at position %d. "
+ "Missing TYPE_END?", t, idx+1);
+ }
+
+ idx++;
+ }
+
+ va_end(ap);
+
+ return 0;
+}
+
+#ifdef TEST_LUAUTIL
+//deps:
+//cflags: $(LUA_CFLAGS) -I..
+//libs: $(LUA_LIBS)
+#include "test.h"
+
+#define LUAPROG \
+ "testfunc('a string', 42, true)"
+
+#define LUAPROG_BAD1 \
+ "testfunc('a string', 42)"
+
+#define LUAPROG_BAD2 \
+ "testfunc('a string', 42, true, 'another one')"
+
+#define LUAPROG_BAD3 \
+ "testfunc(false, 42, 'string')"
+
+#define LUAPROG_MISSING_END \
+ "testfunc_bad('a string', 42, true, 1)"
+
+static int testfunc(lua_State *L)
+{
+ Pracro::checkParameters(L,
+ Pracro::T_STRING,
+ Pracro::T_NUMBER,
+ Pracro::T_BOOLEAN,
+ Pracro::T_END);
+ return 0;
+}
+
+static int testfunc_bad(lua_State *L)
+{
+ Pracro::checkParameters(L,
+ Pracro::T_STRING,
+ Pracro::T_NUMBER,
+ Pracro::T_BOOLEAN,
+ Pracro::T_NUMBER);
+ return 0;
+}
+
+
+TEST_BEGIN;
+
+int a, b, c;
+
+lua_State *L;
+L = luaL_newstate();
+if(L == NULL) TEST_FATAL("Could not allocate lua state.");
+luaL_openlibs(L);
+
+Pracro::setGlobal(L, "a", &a);
+Pracro::setGlobal(L, "b", &b);
+Pracro::setGlobal(L, "c", &c);
+
+TEST_EQUAL(Pracro::getGlobal(L, "b"), &b, "Test get global");
+TEST_EQUAL(Pracro::getGlobal(L, "c"), &c, "Test get global");
+TEST_EQUAL(Pracro::getGlobal(L, "a"), &a, "Test get global");
+
+lua_register(L, "testfunc", testfunc);
+
+if(luaL_loadstring(L, LUAPROG)) {
+ TEST_FATAL(lua_tostring(L, lua_gettop(L)))
+}
+TEST_EQUAL_INT(lua_pcall(L, 0, LUA_MULTRET, 0), 0, "Good one");
+
+if(luaL_loadstring(L, LUAPROG_BAD1)) {
+ TEST_FATAL(lua_tostring(L, lua_gettop(L)))
+}
+TEST_NOTEQUAL_INT(lua_pcall(L, 0, LUA_MULTRET, 0), 0, "Too short one");
+
+if(luaL_loadstring(L, LUAPROG_BAD2)) {
+ TEST_FATAL(lua_tostring(L, lua_gettop(L)))
+}
+TEST_NOTEQUAL_INT(lua_pcall(L, 0, LUA_MULTRET, 0), 0, "Too long one");
+
+if(luaL_loadstring(L, LUAPROG_BAD3)) {
+ TEST_FATAL(lua_tostring(L, lua_gettop(L)))
+}
+TEST_NOTEQUAL_INT(lua_pcall(L, 0, LUA_MULTRET, 0), 0, "Plain wrong");
+
+
+lua_register(L, "testfunc_bad", testfunc_bad);
+if(luaL_loadstring(L, LUAPROG_MISSING_END)) {
+ TEST_FATAL(lua_tostring(L, lua_gettop(L)))
+}
+TEST_NOTEQUAL_INT(lua_pcall(L, 0, LUA_MULTRET, 0), 0, "Missing T_END");
+
+lua_close(L);
+
+TEST_END;
+
+#endif/*TEST_LUAUTIL*/
diff --git a/server/src/luautil.h b/server/src/luautil.h
new file mode 100644
index 0000000..ebbba45
--- /dev/null
+++ b/server/src/luautil.h
@@ -0,0 +1,81 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * luautil.h
+ *
+ * Fri Apr 13 14:38:53 CEST 2007
+ * Copyright 2007 Bent Bisballe Nyeng
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of Pracro.
+ *
+ * Pracro 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 of the License, or
+ * (at your option) any later version.
+ *
+ * Pracro 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 Pracro; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#ifndef __PRACRO_LUAUTIL_H__
+#define __PRACRO_LUAUTIL_H__
+
+#include <lua.hpp>
+#include <lauxlib.h>
+
+#include <string>
+
+namespace Pracro {
+
+ /**
+ * Set a global pointer that can be reaced from the cFunctions at a later time,
+ * using the getGlobal function.
+ * @param L The lua_State (active program) from which to get the pointer.
+ * @param name The symbolic name in which to store the pointer.
+ * @param p The pointer to set.
+ */
+ void setGlobal(lua_State *L, std::string name, void *p);
+
+ /**
+ * Get a global pointer set by the setGlobal function.
+ * @param L The lua_State (active program) in which to set the pointer.
+ * @param name The symbolic name in which the pointer is stored.
+ * @return The pointer.
+ */
+ void *getGlobal(lua_State *L, std::string name);
+
+ /**
+ * Call a function in a lua program.
+ * @param L The lua_State (active program) in which to set the function resides.
+ * @param function The name of the function to be called.
+ */
+ void call(lua_State *L, std::string function, int numargs = 0);
+
+ typedef enum {
+ T_STRING,
+ T_NUMBER,
+ T_BOOLEAN,
+ T_END
+ } types_t;
+
+ /**
+ * Check parameter types and number.
+ * @param L The lua_State (active program) in which to set the function resides.
+ * @param types The type list (c-vector), describing the required types
+ * on the stack. The last type must be a terminating T_END.
+ * @return 0 on success. On error a long jump is made through lua_error, thus
+ * the function never returns.
+ */
+ // int checkParameters(lua_State *L, types_t types[]);
+ int checkParameters(lua_State *L, ...);
+
+};
+
+#endif/*__PRACRO_LUAUTIL_H__*/
diff --git a/server/src/macrolist.cc b/server/src/macrolist.cc
index b67f239..908de1e 100644
--- a/server/src/macrolist.cc
+++ b/server/src/macrolist.cc
@@ -27,80 +27,39 @@
*/
#include "macrolist.h"
-#include <sys/types.h>
-#include <dirent.h>
+#include <utility>
-#include "debug.h"
#include "macroheaderparser.h"
-static std::vector<std::string> listdir(std::string path)
-{
- std::vector<std::string> files;
-
- DIR* dir = opendir(path.c_str());
- if(!dir) {
- PRACRO_ERR(dump, "Could not open directory: %s\n", path.c_str());
- return files;
- }
-
- struct dirent *d;
- while((d = readdir(dir)) != 0) {
- //if(d->d_type == DT_DIR) {
- std::string name = d->d_name;
- if(name.length() >= 4 && name.substr(name.length() - 4) == ".xml")
- files.push_back(name);
- //}
- }
- closedir(dir);
+#include "debug.h"
- return files;
+MacroList::MacroList(std::string path)
+ : EntityList(path, "macro")
+{
+ rescan();
}
-MacroList::MacroList(std::string macropath)
+
+void MacroList::addFile(std::string file)
{
- this->macropath = macropath;
- std::vector<std::string> macros = listdir(macropath);
- std::vector<std::string>::iterator i = macros.begin();
- while(i != macros.end()) {
- MacroHeaderParser parser(macropath + "/" + *i);
- try {
- parser.parse();
- Macro *macro = parser.getMacro();
- (*this)[macro->attributes["name"]][VersionStr(macro->attributes["version"])] = *i;
- } catch(Exception &e) {
- PRACRO_WARN(macrolist, "Skipping %s: %s\n", i->c_str(), e.what());
- }
- i++;
+ if(file.substr(file.size() - 4) != ".xml") {
+ PRACRO_DEBUG(macrolist, "Skipping file: %s\n", file.c_str());
+ return;
}
- {
- iterator i = begin();
- while(i != end()) {
- MacroListItem::iterator j = i->second.begin();
- while(j != i->second.end()) {
- PRACRO_DEBUG(macrolist, "%s - v%s file: %s\n",
- i->first.c_str(),
- ((std::string)j->first).c_str(),
- j->second.c_str());
- j++;
- }
- i++;
- }
+ PRACRO_DEBUG(macrolist, "Adding file: %s\n", file.c_str());
+ MacroHeaderParser parser(file);
+ try {
+ parser.parse();
+ Macro *macro = parser.getMacro();
+ insertEntity(macro->attributes["name"],
+ macro->attributes["version"],
+ file);
+ } catch(Exception &e) {
+ PRACRO_WARN(macrolist, "Skipping %s: %s\n", file.c_str(), e.what());
}
}
-std::string MacroList::getLatestVersion(std::string macro) throw(Exception)
-{
- if(find(macro) == end()) throw Exception("Macro ["+macro+"] does not exist");
- MacroListItem mli = (*this)[macro];
- if(mli.size() == 0) return "";
- PRACRO_DEBUG(macrolist, "Search for %s - found %s v%s\n",
- macro.c_str(),
- (macropath + "/" + mli.begin()->second).c_str(),
- ((std::string)mli.begin()->first).c_str());
- return macropath + "/" + mli.begin()->second;
-}
-
#ifdef TEST_MACROLIST
#define MACRODIR "/home" // We assume this directory exists and does not contain any xml files!
diff --git a/server/src/macrolist.h b/server/src/macrolist.h
index 9b9b0d2..51a30ec 100644
--- a/server/src/macrolist.h
+++ b/server/src/macrolist.h
@@ -28,45 +28,14 @@
#ifndef __PRACRO_MACROLIST_H__
#define __PRACRO_MACROLIST_H__
-#include <map>
-#include <string>
-#include "versionstr.h"
+#include "entitylist.h"
-#include "exception.h"
-
-/**
- * The Items contained in the MacroList.
- */
-typedef std::map<VersionStr, std::string> MacroListItem;
-
-/**
- * The MacroList class is intended for macro file caching, so that all macros
- * do not need to be parsed on each macro query.
- * It builds a list of macros and versions based on the informations read from
- * the MacroHeaderParser.
- * This means that just because a macro gets into the list doesn't means that it
- * will validate as a correct macro (not even nessecarily correct XML).
- */
-class MacroList : public std::map<std::string, MacroListItem > {
+class MacroList : public EntityList {
public:
- /**
- * Constructor.
- * @param macropath A std::string containing the path in which we should look
- * for xml files.
- */
- MacroList(std::string macropath);
-
- /**
- * Convenience method, to gain the filename of the latest version of a given macro.
- * This method throws an Exception if the macro does not exist in the tree.
- * @param macro A std::string containing the name of the wanted macro.
- * @return A std::string containing the file containing the macro with full path
- * included.
- */
- std::string getLatestVersion(std::string macro) throw(Exception);
+ MacroList(std::string path);
-private:
- std::string macropath;
+protected:
+ void addFile(std::string file);
};
#endif/*__PRACRO_MACROLIST_H__*/
diff --git a/server/src/mutex.cc b/server/src/mutex.cc
index 2cc75cc..ec0d0e8 100644
--- a/server/src/mutex.cc
+++ b/server/src/mutex.cc
@@ -37,21 +37,89 @@ Mutex::~Mutex()
pthread_mutex_destroy(&mutex);
}
+bool Mutex::trylock()
+{
+ return pthread_mutex_trylock(&mutex) == 0;
+}
+
void Mutex::lock()
{
- pthread_mutex_lock( &mutex );
+ pthread_mutex_lock(&mutex);
}
void Mutex::unlock()
{
- pthread_mutex_unlock( &mutex );
+ pthread_mutex_unlock(&mutex);
+}
+
+
+MutexAutolock::MutexAutolock(Mutex &m)
+ : mutex(m)
+{
+ mutex.lock();
+}
+
+MutexAutolock::~MutexAutolock()
+{
+ mutex.unlock();
}
#ifdef TEST_MUTEX
+//deps:
+//cflags: $(PTHREAD_CFLAGS)
+//libs: $(PTHREAD_LIBS)
+#include <test.h>
-int main()
+#include <unistd.h>
+
+volatile int cnt = 0;
+
+static void* thread_run(void *data)
{
- return 0;
+ Mutex *mutex = (Mutex*)data;
+ mutex->lock();
+ cnt++;
+ mutex->unlock();
+ return NULL;
}
+TEST_BEGIN;
+
+Mutex mutex;
+
+mutex.lock();
+TEST_FALSE(mutex.trylock(), "Testing if trylock works negative.");
+mutex.unlock();
+TEST_TRUE(mutex.trylock(), "Testing if trylock works positive.");
+mutex.unlock();
+
+mutex.lock();
+
+pthread_attr_t attr;
+pthread_t tid;
+pthread_attr_init(&attr);
+pthread_create(&tid, &attr, thread_run, &mutex);
+
+sleep(1);
+TEST_EQUAL_INT(cnt, 0, "Testing if lock prevent cnt from increasing.");
+mutex.unlock();
+
+sleep(1);
+TEST_EQUAL_INT(cnt, 1, "Testing if unlock makes cnt increase.");
+
+pthread_join(tid, NULL);
+pthread_attr_destroy(&attr);
+
+{
+ TEST_TRUE(mutex.trylock(), "Testing if autolock has not yet locked the mutex.");
+ mutex.unlock();
+ MutexAutolock mlock(mutex);
+ TEST_FALSE(mutex.trylock(), "Testing if autolock worked.");
+}
+
+TEST_TRUE(mutex.trylock(), "Testing if autolock has released the lock on the mutex.");
+mutex.unlock();
+
+TEST_END;
+
#endif/*TEST_MUTEX*/
diff --git a/server/src/mutex.h b/server/src/mutex.h
index 8b35042..cf052ad 100644
--- a/server/src/mutex.h
+++ b/server/src/mutex.h
@@ -35,6 +35,7 @@ public:
Mutex();
~Mutex();
+ bool trylock();
void lock();
void unlock();
@@ -42,4 +43,13 @@ private:
pthread_mutex_t mutex;
};
+class MutexAutolock {
+public:
+ MutexAutolock(Mutex &mutex);
+ ~MutexAutolock();
+
+private:
+ Mutex &mutex;
+};
+
#endif/*__PRACRO_MUTEX_H__*/
diff --git a/server/src/pracrod.cc b/server/src/pracrod.cc
index d17001c..e15b0f0 100644
--- a/server/src/pracrod.cc
+++ b/server/src/pracrod.cc
@@ -89,6 +89,7 @@ static const char usage_str[] =
" -h, --help Print this message and exit.\n"
" -D, --debug ddd Enable debug messages on 'ddd'; see documentation for details\n"
" -d --database db Use db as the database backend. Can be one of pgsql or testdb (default pgsql).\n"
+" -s, --ssl keyfile Enable ssl encryption with the key stored in keyfile.\n"
;
ConfigurationParser *configparser = NULL;
@@ -137,6 +138,39 @@ int PracroDaemon::daemon_main()
return 0;
}
+#define CERT "\
+-----BEGIN CERTIFICATE-----\n\
+MIICFTCCAX6gAwIBAgIBAjANBgkqhkiG9w0BAQUFADBVMRswGQYDVQQKExJBcGFj\n\
+aGUgSFRUUCBTZXJ2ZXIxIjAgBgNVBAsTGUZvciB0ZXN0aW5nIHB1cnBvc2VzIG9u\n\
+bHkxEjAQBgNVBAMTCWxvY2FsaG9zdDAeFw0wNzA2MjEwODE4MzZaFw0wODA2MjAw\n\
+ODE4MzZaMEwxGzAZBgNVBAoTEkFwYWNoZSBIVFRQIFNlcnZlcjEZMBcGA1UECxMQ\n\
+VGVzdCBDZXJ0aWZpY2F0ZTESMBAGA1UEAxMJbG9jYWxob3N0MIGfMA0GCSqGSIb3\n\
+DQEBAQUAA4GNADCBiQKBgQDWTACKSoxd5cL06w7RtPIhFqY1l3UE/aRGmPmh8gEo\n\
+w3zNf+gWxco2yjQgBTQhGww1ybOsAUtXPIsUOSFAGvPUKJZf8ibZMiJEzl2919uz\n\
+IcV9+cUm7k3jFPQx4ALQEalbV++o/lfT5lhgsSiH1t1eln2omVrGCjI/1HeYrw7X\n\
+owIDAQABMA0GCSqGSIb3DQEBBQUAA4GBALVFzprK6rYkWVZZZwq85w2lCYJpEl9a\n\
+66IMzIwNNRfyZMoc9D9PSwsXKYfYOg1RpMt7RhWT/bpggGlsFqctsAgJSv8Ol5Cz\n\
+DqTXhpV+8WOG6l4xDYZz3U3ajiu2jth2+aaMuWKy9Wkr8bzHGDufltToLalucne2\n\
+npM7yCJ83Ana\n\
+-----END CERTIFICATE-----"
+
+#define KEY "\
+-----BEGIN RSA PRIVATE KEY-----\n\
+MIICXAIBAAKBgQDWTACKSoxd5cL06w7RtPIhFqY1l3UE/aRGmPmh8gEow3zNf+gW\n\
+xco2yjQgBTQhGww1ybOsAUtXPIsUOSFAGvPUKJZf8ibZMiJEzl2919uzIcV9+cUm\n\
+7k3jFPQx4ALQEalbV++o/lfT5lhgsSiH1t1eln2omVrGCjI/1HeYrw7XowIDAQAB\n\
+AoGANUXHjJljs6P+hyw4DuHQn3El+ISiTo9PW02EIUIsD5opWFzHsYGR93Tk6GDi\n\
+yKgUrPprdAMOW61tVaWuImWQ32R2xyrJogjGYo9XE2xAej9N37jM0AGBtn/vd4Dr\n\
+LsYfpjNaM3gqIChD73iYfO+CrNbdLqTxIdG53g/u05GJ4cECQQD0vMm5+a8N82Jb\n\
+oHJgE2jb83WqaYBHe0O03ujtiq3+hPZHoVV3iJWmA/aMlgdtunkJT3PdEsVfQNkH\n\
+fvzR9JhbAkEA4CiZRk5Gcz7cEqyogDTMQYtmrE8hbgofISLuz1rpTEzd8hFAcerU\n\
+nuwFIT3go3hO7oIHMlKU1H5iT1BsFvegWQJBAOSa6A+5A+STIKAX+l52Iu+5tYKN\n\
+885RfMgZpBgm/yoMxwPX1r7GLYsajpV5mszLbz3cIo0xeH3mVBOlccEoqZsCQECP\n\
+8PWq/eebp09Jo46pplsKh5wBfqNvDuBAa4AVszRiv1pFVcZ52JudZyzX4aezsyhH\n\
+E0OPPYamkDI/+6Hx2KECQHF9xV1XatyXuFmfRAInK2BtfGY5UIvJaLxVD3Z1+i6q\n\
+/enz7/wUwvC6G4FSWNMYgAYJOfwZ3BerdkqcRNxyR/Q=\n\
+-----END RSA PRIVATE KEY-----"
+
int main(int argc, char *argv[])
{
int c;
@@ -163,10 +197,11 @@ int main(int argc, char *argv[])
{"xml-basedir", required_argument, 0, 'x'},
{"debug", required_argument, 0, 'D'},
{"database", required_argument, 0, 'd'},
+ {"ssl", required_argument, 0, 's'},
{0, 0, 0, 0}
};
- c = getopt_long (argc, argv, "D:hvfc:u:g:x:d:", long_options, &option_index);
+ c = getopt_long (argc, argv, "D:hvfc:u:g:x:d:s:", long_options, &option_index);
if (c == -1)
break;
@@ -200,6 +235,17 @@ int main(int argc, char *argv[])
debugstr = strdup(optarg);
break;
+ case 's':
+#ifdef WITHOUT_SSL
+ PRACRO_ERR(server, "Pracro was not compiled with SSL support!\n");
+ return 1;
+#else
+ Conf::use_ssl = true;
+ Conf::ssl_key = KEY;
+ Conf::ssl_cert = CERT;
+#endif
+ break;
+
case '?':
case 'h':
printf("%s", version_str);
@@ -228,6 +274,11 @@ int main(int argc, char *argv[])
Conf::database_backend = database;
}
+ if(Conf::database_backend == "testdb") {
+ // Test db (memory only db) does not work in plural.
+ Conf::database_poolsize = 1;
+ }
+
if(!user) {
user = strdup(Conf::server_user.c_str());
}
diff --git a/server/src/queryhandlerpentominos.cc b/server/src/queryhandlerpentominos.cc
index c5450b3..b67f731 100644
--- a/server/src/queryhandlerpentominos.cc
+++ b/server/src/queryhandlerpentominos.cc
@@ -28,103 +28,241 @@
#include "debug.h"
-#include "configuration.h"
+#include <config.h>
-QueryHandlerPentominos::QueryHandlerPentominos(std::string cpr)
- : QueryHandler()
+// For time
+#include <time.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+// For getpid
+#include <unistd.h>
+#include <sys/types.h>
+
+// For time
+#include <time.h>
+
+// For strerror and errno
+#include <errno.h>
+
+// For socket and friends
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <net/if.h>
+#include <netinet/in.h>
+
+// For ioctl
+#include <sys/ioctl.h>
+
+#include "queryparser.h"
+
+typedef struct {
+ in_addr_t ip;
+ time_t time;
+ pid_t pid;
+ unsigned short int count;
+} UID;
+
+#define SIOCGIFCONF 0x8912 // get iface list
+/*
+static in_addr_t getIP(const char *interface)
{
- this->cpr = cpr;
+ in_addr_t ret = 0;
+ int numreqs = 30, sd, n;
+ struct ifconf ifc;
+ struct ifreq *ifr;
+ struct in_addr *ia;
- atfh = atf_init();
+ sd = socket(AF_INET, SOCK_STREAM, 0);
+ if(sd == -1) {
+ // throw Pentominos::UIDCouldNotConnectException(strerror(errno));
+ }
+
+ ifc.ifc_buf = NULL;
+ ifc.ifc_len = sizeof(struct ifreq) * numreqs;
+
+ ifc.ifc_buf = (char*)malloc(ifc.ifc_len);
+ if(ifc.ifc_buf == NULL) {
+ // throw Pentominos::UIDOutOfMemoryException();
+ }
+
+ if (ioctl(sd, SIOCGIFCONF, &ifc) < 0) {
+ // throw Pentominos::UIDInterfaceListException(strerror(errno));
+ }
- bool use_https = false;
- atfc = atf_connect(atfh, Conf::pentominos_addr.c_str(),
- Conf::pentominos_port, use_https);
+ ifr = ifc.ifc_req;
+ for (n = 0; n < ifc.ifc_len; n += sizeof(struct ifreq)) {
+ ia = (struct in_addr *)((ifr->ifr_ifru.ifru_addr.sa_data)+2);
+ if(!strcmp(ifr->ifr_ifrn.ifrn_name, interface)) {
+ ret = *(in_addr_t*)ia;
+ }
+ ifr++;
+ }
+ if(!ret) { // Still no interface... We're fucked!
+ // throw Pentominos::UIDInterfaceException(interface);
+ }
+
+ free(ifc.ifc_buf);
+ return ret;
}
-QueryHandlerPentominos::~QueryHandlerPentominos()
+
+static unsigned short counter = 0;
+static unsigned short getCounter()
{
- atf_disconnect(atfc);
- atf_close(atfh);
+ return counter++;
}
-static QueryResult node2result(atf_result_node_t *node, time_t timestamp)
+
+static UID uid = {0,0,0,0};
+static std::string getUID(const char *interface)
{
- QueryResult rnode;
- rnode.timestamp = timestamp;
- rnode.source = "pentominos";
-
- if(!node) return rnode;
-
- struct _atf_result_node_t *child = node->child;
- while(child) {
- if(child->value == NULL) {
- rnode.groups[child->name] = node2result(child, timestamp);
- } else {
- rnode.values[child->name] = child->value;
- }
- child = child->next;
- }
+ if(!uid.ip) uid.ip = getIP(interface);
+
+ time_t t = time(NULL);
+ if(uid.time != t) counter = 0; // If time differes, reset the counter
+ uid.time = t; // We need this value every time.
+
+ if(!uid.pid) uid.pid = getpid();
- return rnode;
+ uid.count = getCounter();
+
+ char buf[32];
+ sprintf(buf, "%08x%08x%04x%04x", uid.ip, (unsigned int)uid.time, uid.pid, uid.count);
+ return std::string(buf);
+}
+*/
+
+QueryHandlerPentominos::QueryHandlerPentominos(Artefact &atf,
+ std::string patientid,
+ std::string user)
+ : QueryHandler(), artefact(atf)
+{
+ this->patientid = patientid;
+ this->user = user;
}
QueryResult QueryHandlerPentominos::exec(Query &query)
{
- atf_transaction_t* atft = NULL;
- atf_reply_t *reply = NULL;
- atf_result_t *result = NULL;
- atf_result_node_t *root = NULL;
- atf_status_t status;
- time_t timestamp;
- atf_id id;
+ return artefact.exec(query, patientid, user);
+
+#if 0
+ time_t timestamp = time(NULL);
+ std::string uid = getUID("eth0");
- QueryResult rroot;
- rroot.timestamp = timestamp;
- rroot.source = "pentominos";
+ char buf[512];
+ char header[] =
+ "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<artefact xmlns=\"http://www.aasimon.org/pentominos\"\n"
+ " xmlns:pentominos=\"http://www.aasimon.org/pentominos\"\n"
+ " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"
+ " xsi:schemaLocation=\"http://www.aasimon.org/pentominos schema.xsd\">\n";
+#ifndef WITHOUT_PENTOMINOS
+ artefact.socket.write(header, strlen(header));
+#endif/*WITHOUT_PENTOMINOS*/
- atft = atf_new_transaction(atfc, cpr.c_str());
- if(!atft) goto aaarg;
+ PRACRO_DEBUG(queryhandler, "%s", header);
- id = atf_add_query(atft, query.attributes["class"].c_str(),
- FILTER_LATEST, USE_NONE, 0, 0);
- if(!atft) goto aaarg;
+ sprintf(buf, " <pentominos:entry replyformat=\"xml\"\n"
+ " cpr=\"%s\"\n"
+ " operator=\"%s\"\n"
+ " src_addr=\"%s\"\n"
+ " dst_addr=\"%s\"\n"
+ " timestamp=\"%d\"\n"
+ " uid=\"%s\"/>\n",
+ cpr.c_str(),
+ "pracro",
+#ifndef WITHOUT_PENTOMINOS
+ artefact.socket.srcaddr().c_str(),
+ artefact.socket.dstaddr().c_str(),
+#else
+ "127.0.0.1",
+ "127.0.0.1",
+#endif/*WITHOUT_PENTOMINOS*/
+ (unsigned int)timestamp,
+ uid.c_str());
+#ifndef WITHOUT_PENTOMINOS
+ artefact.socket.write(buf, strlen(buf));
+#endif/*WITHOUT_PENTOMINOS*/
- reply = atf_commit(atft);
- if(!reply) goto aaarg;
+ PRACRO_DEBUG(queryhandler, "%s", buf);
- if(atf_get_num_results(reply, id) != 1) goto aaarg;
+ sprintf(buf, " <pentominos:query device_id=\"%s\"\n"
+ " device_type=\"%s\"\n"
+ " filter=\"latest\"\n"
+ " location=\"all\"/>\n",
+ query.attributes["class"].c_str(),
+ query.attributes["class"].c_str());
+
+#ifndef WITHOUT_PENTOMINOS
+ artefact.socket.write(buf, strlen(buf));
+#endif/*WITHOUT_PENTOMINOS*/
- result = atf_get_result(reply, id, 0);
- if(!result) goto aaarg;
+ PRACRO_DEBUG(queryhandler, "%s", buf);
- status = atf_get_result_status(result, NULL, 0);
- if(status != ATF_STATUS_OK) goto aaarg;
-
- timestamp = atf_get_result_timestamp(result);
+ sprintf(buf, "</artefact>");
- root = atf_get_result_node(result);
- if(!root) goto aaarg;
+#ifndef WITHOUT_PENTOMINOS
+ artefact.socket.write(buf, strlen(buf));
+#endif/*WITHOUT_PENTOMINOS*/
- {
- QueryResult qresult = node2result(root, timestamp);
- rroot.groups[query.attributes["class"]] = qresult;
+ PRACRO_DEBUG(queryhandler, "%s", buf);
+
+ QueryResult result;
+
+#ifndef WITHOUT_PENTOMINOS
+ QueryParser parser;
+
+ ssize_t size;
+
+ // Read until we've got the entire result.
+ while((size = artefact.socket.read(buf, sizeof(buf))) > 0) {
+ // fwrite(buf, size, 1, stdout); fflush(stdout);
+ if(parser.parse(buf, size)) break;
}
- aaarg:
- if(root) atf_free_result_node(root);
- if(reply) atf_free_reply(reply);
- if(atft) atf_free_transaction(atft);
+ result = parser.result;
+#endif/*WITHOUT_PENTOMINOS*/
+
+ PRACRO_INFO(queryhandler, "Done handling query\n");
+
+ result.print();
- return rroot;
+ return result;
+#endif
+ return QueryResult();
}
#ifdef TEST_QUERYHANDLERPENTOMINOS
int main()
{
+#ifdef WITHOUT_PENTOMINOS
+ printf("The project need to be configured for use of Pentominos in order to run this test.\n");
return 1;
+#endif/*WITHOUT_PENTOMINOS*/
+
+ TCPSocket s;
+ try {
+ s.connect("localhost", 11108);
+ } catch(Exception &e) {
+ printf("ERROR: %s\n", e.what());
+ printf("A running instance of the artefact server in needed on localhost, port 11108 in order for this test to run.\n");
+ return 1;
+ }
+
+ QueryHandlerPentominos qh(s, "2003791613");
+
+ Query q1;
+ q1.attributes["device_id"] = "lensmeter";
+ q1.attributes["device_type"] = "lensmeter";
+ QueryResult res = qh.exec(q1);
+ res.print();
+
+ return 0;
}
#endif/*TEST_QUERYHANDLERPENTOMINOS*/
diff --git a/server/src/queryhandlerpentominos.h b/server/src/queryhandlerpentominos.h
index 53b01ad..b96c097 100644
--- a/server/src/queryhandlerpentominos.h
+++ b/server/src/queryhandlerpentominos.h
@@ -29,29 +29,30 @@
#include "queryhandler.h"
+#include "artefact.h"
#include "template.h"
#include "queryresult.h"
+#include <vector>
#include <string>
-#include <libartefact.h>
-
/**
* This class handles the query of external data.
*/
class QueryHandlerPentominos : public QueryHandler {
public:
- QueryHandlerPentominos(std::string cpr);
- ~QueryHandlerPentominos();
+ QueryHandlerPentominos(Artefact &artefact,
+ std::string patientid,
+ std::string user);
+ ~QueryHandlerPentominos() {}
// Execute all queries.
QueryResult exec(Query &query);
private:
- atf_handle_t *atfh;
- atf_connection_t *atfc;
-
- std::string cpr;
+ Artefact &artefact;
+ std::string patientid;
+ std::string user;
};
#endif/*__PRACRO_QUERYHANDLERPENTOMINOS_H__*/
diff --git a/server/src/queryparser.cc b/server/src/queryparser.cc
new file mode 100644
index 0000000..db562ae
--- /dev/null
+++ b/server/src/queryparser.cc
@@ -0,0 +1,168 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * queryparser.cc
+ *
+ * Tue May 6 17:02:37 CEST 2008
+ * Copyright 2008 Bent Bisballe Nyeng
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of Pracro.
+ *
+ * Pracro 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 of the License, or
+ * (at your option) any later version.
+ *
+ * Pracro 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 Pracro; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#include "queryparser.h"
+
+QueryParser::QueryParser()
+{
+ this->timestamp = 0;
+
+ p = 0;
+ stack.push_back(&result);
+}
+
+void QueryParser::startTag(std::string name, std::map< std::string, std::string> attributes)
+{
+
+ if(name == "results") {
+ // What to do here!?
+ }
+
+ if(name == "result") {
+ this->timestamp = atol(attributes["timestamp"].c_str());
+
+ QueryResult q;
+ q.source = "pentominos";
+ q.timestamp = this->timestamp;
+ stack.back()->groups[attributes["class"]] = q;
+ stack.push_back(&stack.back()->groups[attributes["class"]]);
+ }
+
+ if(name == "group") {
+ QueryResult q;
+ q.timestamp = this->timestamp;
+ stack.back()->groups[attributes["name"]] = q;
+ stack.push_back(&stack.back()->groups[attributes["name"]]);
+ }
+
+ if(name == "value") {
+ stack.back()->values[attributes["name"]] = utf8.decode(attributes["value"]);
+ }
+
+}
+
+void QueryParser::endTag(std::string name)
+{
+ if(name == "group" || name == "result") stack.pop_back();
+}
+
+void QueryParser::parseError(const char *buf, size_t len, std::string error, int lineno)
+{
+ fprintf(stderr, "QueryParser error at line %d: %s\n", lineno, error.c_str());
+ fprintf(stderr, "\tBuffer %u bytes: [", len);
+ if(fwrite(buf, len, 1, stderr) != len) {}
+ fprintf(stderr, "]\n");
+ fflush(stderr);
+
+ char *slineno;
+ if(asprintf(&slineno, " at line %d\n", lineno) != -1) {
+ throw Exception(error + slineno);
+ free(slineno);
+ }
+
+}
+
+#ifdef TEST_QUERYPARSER
+
+#include <string.h>
+
+static char xml[] =
+ "<?xml version='1.0' encoding='UTF-8'?>\n"
+ "<results>\n"
+ " <result class=\"testclass\" timestamp=\"1234567890\">\n"
+ " <group name=\"testgroup\">\n"
+ " <value name=\"testvalue\" value=\"42\"/>\n"
+ " <value name=\"anothertestvalue\" value=\"42\"/>\n"
+ " </group>\n"
+ " <group name=\"anothertestgroup\">\n"
+ " <value name=\"testvalue\" value=\"42\"/>\n"
+ " <value name=\"anothertestvalue\" value=\"42\"/>\n"
+ " </group>\n"
+ " </result>\n"
+ " <result class=\"anothertestclass\" timestamp=\"1234567890\">\n"
+ " <group name=\"testgroup\">\n"
+ " <value name=\"testvalue\" value=\"42\"/>\n"
+ " <value name=\"anothertestvalue\" value=\"42\"/>\n"
+ " </group>\n"
+ " <group name=\"anothertestgroup\">\n"
+ " <value name=\"testvalue\" value=\"42\"/>\n"
+ " <value name=\"anothertestvalue\" value=\"42\"/>\n"
+ " </group>\n"
+ " </result>\n"
+ "</results>\n"
+;
+
+static char badxml[] =
+ "<?xml version='1.0' encoding='UTF-8'?>\n"
+ "<results>\n"
+ "</sulrets>\n"
+;
+
+static std::string loadresultstring(QueryResult &res, std::string group = "")
+{
+ std::string s;
+
+ std::map< std::string, std::string >::iterator v = res.values.begin();
+ while(v != res.values.end()) {
+ s += group + (*v).first + " = \"" + (*v).second + "\"\n";
+ v++;
+ }
+
+ std::map< std::string, QueryResult >::iterator g = res.groups.begin();
+ while(g != res.groups.end()) {
+ s += group + (*g).first + " = {}\n";
+ s += loadresultstring((*g).second, group + (*g).first + ".");
+ g++;
+ }
+
+ return s;
+}
+
+int main()
+{
+ // Parse something
+ {
+ QueryParser parser;
+ parser.parse(xml, strlen(xml));
+ printf("%s\n", loadresultstring(parser.result).c_str());
+ }
+
+ // Parse something, and fail!
+ try {
+ QueryParser parser;
+ parser.parse(badxml, strlen(badxml));
+ printf("%s\n", loadresultstring(parser.result).c_str());
+ } catch(Exception &e) {
+ printf("ERROR: %s\n", e.what());
+ goto weitergehen;
+ }
+ return 1;
+ weitergehen:
+
+ return 0;
+}
+
+#endif/*TEST_QUERYPARSER*/
diff --git a/server/src/queryparser.h b/server/src/queryparser.h
new file mode 100644
index 0000000..f901d2c
--- /dev/null
+++ b/server/src/queryparser.h
@@ -0,0 +1,81 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * queryparser.h
+ *
+ * Tue May 6 17:02:36 CEST 2008
+ * Copyright 2008 Bent Bisballe Nyeng
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of Pracro.
+ *
+ * Pracro 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 of the License, or
+ * (at your option) any later version.
+ *
+ * Pracro 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 Pracro; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#ifndef __PRACRO_QUERYPARSER_H__
+#define __PRACRO_QUERYPARSER_H__
+
+#include "saxparser.h"
+
+#include <time.h>
+#include <vector>
+
+#include "queryresult.h"
+#include "utf8.h"
+#include "exception.h"
+
+/**
+ * This class parses xml entities into a QueryResult structure.
+ * Call the parent (SAXParser) method parse in order to actually parse something.
+ * If the parser fails (syntax error) it will throw an Exception.
+ * @see QueryResult result, in order to get the parsed data.
+ */
+class QueryParser : public SAXParser {
+public:
+ /**
+ * Constructor.
+ */
+ QueryParser();
+
+ /**
+ * The object will contain the result when the parsing is done.
+ */
+ QueryResult result;
+
+ /**
+ * Private parser callback.
+ */
+ void startTag(std::string name, std::map< std::string, std::string> attributes);
+
+ /**
+ * Private parser callback.
+ */
+ void endTag(std::string name);
+
+ /**
+ * Private parser callback.
+ */
+ void parseError(const char *buf, size_t len, std::string error, int lineno);
+
+private:
+ // For read
+ int p;
+ std::string document;
+ time_t timestamp;
+ std::vector< QueryResult * > stack;
+ UTF8 utf8;
+};
+
+#endif/*__PRACRO_QUERYPARSER_H__*/
diff --git a/server/src/resumeparser.cc b/server/src/resumeparser.cc
index bf3483e..4d514ac 100644
--- a/server/src/resumeparser.cc
+++ b/server/src/resumeparser.cc
@@ -26,9 +26,10 @@
*/
#include "resumeparser.h"
-#include "luaresume.h"
#include <string.h>
+#include "luaresume.h"
+
static std::string resume_parser_format(Resume &r, Commit &commit)
{
const char* format = r.attributes["format"].c_str();
diff --git a/server/src/saxparser.cc b/server/src/saxparser.cc
index 9072ab6..f26c965 100644
--- a/server/src/saxparser.cc
+++ b/server/src/saxparser.cc
@@ -74,7 +74,7 @@ SAXParser::SAXParser()
{
p = XML_ParserCreate(NULL);
if(!p) {
- PRACRO_ERR_LOG(sax, "Couldn't allocate memory for parser\n");
+ PRACRO_ERR(sax, "Couldn't allocate memory for parser\n");
// throw Exception(...);
return;
}
@@ -103,7 +103,8 @@ int SAXParser::parse()
do {
len = readData(buf, sizeof(buf) - 1);
if (! XML_Parse(p, buf, len, len == 0)) {
- parseError(buf, len, XML_ErrorString(XML_GetErrorCode(p)), (int)XML_GetCurrentLineNumber(p));
+ parseError(buf, len, XML_ErrorString(XML_GetErrorCode(p)),
+ (int)XML_GetCurrentLineNumber(p));
return 1;
}
@@ -123,35 +124,43 @@ static bool iswhitespace(const char *buf, size_t size)
bool SAXParser::parse(const char *data, size_t size)
{
- PRACRO_DEBUG(sax, "parse %d bytes\n", size);
+ std::string xml;
+ xml.append(data, size);
+ PRACRO_DEBUG(sax, "parse %d bytes [%s]\n", size, xml.c_str());
bufferbytes = size;
totalbytes += bufferbytes;
if(! XML_Parse(p, data, size, false) ) {
if(XML_GetErrorCode(p) == XML_ERROR_JUNK_AFTER_DOC_ELEMENT) return true;
- if(XML_GetErrorCode(p) == XML_ERROR_FINISHED && iswhitespace(data, size)) return true;
+ if(XML_GetErrorCode(p) == XML_ERROR_FINISHED &&
+ iswhitespace(data, size)) return true;
if(done && XML_GetErrorCode(p) == XML_ERROR_UNCLOSED_TOKEN) return true;
- parseError(data, size, XML_ErrorString(XML_GetErrorCode(p)), (int)XML_GetCurrentLineNumber(p));
+ parseError(data, size, XML_ErrorString(XML_GetErrorCode(p)),
+ (int)XML_GetCurrentLineNumber(p));
return false;
}
if(done) {
if(! XML_Parse(p, data, 0, true) ) {
if(XML_GetErrorCode(p) == XML_ERROR_JUNK_AFTER_DOC_ELEMENT) return true;
- if(XML_GetErrorCode(p) == XML_ERROR_FINISHED && iswhitespace(data, size)) return true;
+ if(XML_GetErrorCode(p) == XML_ERROR_FINISHED &&
+ iswhitespace(data, size)) return true;
if(XML_GetErrorCode(p) == XML_ERROR_UNCLOSED_TOKEN) return true;
- parseError(data, 0, XML_ErrorString(XML_GetErrorCode(p)), (int)XML_GetCurrentLineNumber(p));
+ parseError(data, 0, XML_ErrorString(XML_GetErrorCode(p)),
+ (int)XML_GetCurrentLineNumber(p));
return false;
}
}
- if(done) PRACRO_DEBUG(sax, "Got END_OF_DOCUMENT [%s] at %ld\n", outertag.c_str(), XML_GetCurrentByteIndex(p));
+ if(done) PRACRO_DEBUG(sax, "Got END_OF_DOCUMENT [%s] at %ld\n",
+ outertag.c_str(), XML_GetCurrentByteIndex(p));
return done;
}
-void SAXParser::parseError(const char *buf, size_t len, std::string error, int lineno)
+void SAXParser::parseError(const char *buf, size_t len,
+ std::string error, int lineno)
{
fprintf(stderr, "SAXParser error at line %d: %s\n", lineno, error.c_str());
fprintf(stderr, "\tBuffer %u bytes: [", len);
@@ -167,6 +176,10 @@ unsigned int SAXParser::usedBytes()
#ifdef TEST_SAXPARSER
+//deps: log.cc debug.cc exception.cc
+//cflags: -I..
+//libs: -lexpat
+#include <test.h>
#define XMLFILE "/tmp/saxparsertest.xml"
@@ -253,139 +266,125 @@ public:
}
};
-int main(int argc, char *argv[])
-{
- FILE *fp = fopen(XMLFILE, "w");
- if(!fp) {
- printf("Could not write to %s\n", XMLFILE);
- return 1;
- }
- fprintf(fp, xml);
- fclose(fp);
+TEST_BEGIN;
- // Test callback parser
- {
- MyFileParser parser(XMLFILE);
- parser.parse();
- }
+FILE *fp = fopen(XMLFILE, "w");
+TEST_NOTEQUAL(fp, NULL, "Test if file \""XMLFILE"\" could be written.");
+if(!fp) TEST_FATAL("Could not write "XMLFILE);
+fprintf(fp, "%s", xml);
+fclose(fp);
- // Test buffer parser
- for(size_t sz = 1; sz < 1000; sz++) {
- bool test = false;
- MyBufferParser parser;
- std::string buf = xml;
- size_t pos = 0;
- while(pos < buf.length()) {
- std::string substr = buf.substr(pos, sz);
-
- try {
- test |= parser.parse((char*)substr.c_str(), substr.length());
- } catch(Exception &e) {
- printf("Buffer parser failed on size %d: %s [%s]\n", sz, e.what(), substr.c_str());
- }
- pos += sz;
- }
+TEST_MSG("Test callback parser.");
+{
+ MyFileParser parser(XMLFILE);
+ parser.parse();
+}
- if(!test) {
- printf("Buffer parser failed on size %d\n", sz);
- return 1;
+TEST_MSG("Test buffer parser.");
+for(size_t sz = 1; sz < 1000; sz++) {
+ bool test = false;
+ MyBufferParser parser;
+ std::string buf = xml;
+ size_t pos = 0;
+ while(pos < buf.length()) {
+ std::string substr = buf.substr(pos, sz);
+
+ try {
+ test |= parser.parse((char*)substr.c_str(), substr.length());
+ } catch(Exception &e) {
+ TEST_TRUE(true, "Buffer parser failed on size %d: %s [%s]",
+ sz, e.what(), substr.c_str());
}
+ pos += sz;
}
+
+ TEST_TRUE(test, "Test buffer parser on %d bytes", sz);
+ }
- fp = fopen(XMLFILE, "w");
- if(!fp) {
- printf("Could not write to %s\n", XMLFILE);
- return 1;
- }
- fprintf(fp, xml_notrailingwhitespace);
- fprintf(fp, xml_notrailingwhitespace);
- fclose(fp);
- // Test buffer parser with multiple documents in the same buffer
- {
- fp = fopen(XMLFILE, "r");
- if(!fp) {
- printf("Could not write to %s\n", XMLFILE);
- return 1;
- }
- for(size_t sz = 1; sz < 1000; sz++) {
- MyBufferParser *parser = NULL;
- rewind(fp);
- size_t numdocs = 0;
- char *buf = new char[sz + 1];
- memset(buf, 0, sz + 1);
- size_t size;
- while( (size = fread(buf, 1, sz, fp)) > 0) {
- while(size) {
- if(parser == NULL) {
- parser = new MyBufferParser();
- }
- if(parser->parse(buf, size)) {
-
- // Got one
- numdocs++;
-
- size = size - parser->usedBytes();
- strcpy(buf, buf + parser->usedBytes());
- delete parser; parser = NULL;
- } else {
- size = 0;
- memset(buf, 0, sz + 1);
- }
+fp = fopen(XMLFILE, "w");
+TEST_NOTEQUAL(fp, NULL, "Test if file \""XMLFILE"\" could be written.");
+if(!fp) TEST_FATAL("Could not write "XMLFILE);
+fprintf(fp, "%s", xml_notrailingwhitespace);
+fprintf(fp, "%s", xml_notrailingwhitespace);
+fclose(fp);
+
+TEST_MSG("Test buffer parser with multiple documents in the same buffer.");
+{
+ fp = fopen(XMLFILE, "r");
+ TEST_NOTEQUAL(fp, NULL, "Test if file \""XMLFILE"\" could be read.");
+ if(!fp) TEST_FATAL("Could not read from "XMLFILE);
+
+ for(size_t sz = 1; sz < 1000; sz++) {
+ MyBufferParser *parser = NULL;
+ rewind(fp);
+ size_t numdocs = 0;
+ char *buf = new char[sz + 1];
+ memset(buf, 0, sz + 1);
+ size_t size;
+ while( (size = fread(buf, 1, sz, fp)) > 0) {
+ while(size) {
+ if(parser == NULL) {
+ parser = new MyBufferParser();
+ }
+ if(parser->parse(buf, size)) {
+
+ // Got one
+ numdocs++;
+
+ size = size - parser->usedBytes();
+ strcpy(buf, buf + parser->usedBytes());
+ delete parser; parser = NULL;
+ } else {
+ size = 0;
+ memset(buf, 0, sz + 1);
}
}
- if(numdocs != 2) {
- printf("Failed to parse two documents.\n");
- return 1;
- }
- if(parser) delete parser; parser = NULL;
- delete[] buf;
}
- fclose(fp);
- }
-
- fp = fopen(XMLFILE, "w");
- if(!fp) {
- printf("Could not write to %s\n", XMLFILE);
- return 1;
+ TEST_EQUAL(numdocs, 2, "Test if 2 documents were parsed on docsize %d.", sz);
+ if(parser) delete parser; parser = NULL;
+ delete[] buf;
}
- fprintf(fp, xml_fail);
fclose(fp);
+}
- // Test failure
- {
- MyFileParser parser(XMLFILE);
- try {
- parser.parse();
- } catch(Exception &e) {
- goto goon;
- }
- printf("This test should fail...\n");
- return 1;
- }
- goon:
+fp = fopen(XMLFILE, "w");
+TEST_NOTEQUAL(fp, NULL, "Test if file \""XMLFILE"\" could be written.");
+if(!fp) TEST_FATAL("Could not write "XMLFILE);
+fprintf(fp, "%s", xml_fail);
+fclose(fp);
- fp = fopen(XMLFILE, "w");
- if(!fp) {
- printf("Could not write to %s\n", XMLFILE);
- return 1;
+TEST_MSG("Test failure");
+{
+ MyFileParser parser(XMLFILE);
+ try {
+ parser.parse();
+ } catch(Exception &e) {
+ goto goon;
}
- fprintf(fp, xml_fail2);
- fclose(fp);
+ TEST_TRUE(false, "This test should fail...\n");
+}
+goon:
- // Test failure
- {
- MyFileParser parser(XMLFILE);
- try {
- parser.parse();
- } catch(Exception &e) {
- goto goonagain;
- }
- printf("This test should fail...\n");
- return 1;
- }
- goonagain:
+fp = fopen(XMLFILE, "w");
+TEST_NOTEQUAL(fp, NULL, "Test if file \""XMLFILE"\" could be written.");
+if(!fp) TEST_FATAL("Could not write "XMLFILE);
+fprintf(fp, "%s", xml_fail2);
+fclose(fp);
- unlink(XMLFILE);
+// Test failure
+{
+ MyFileParser parser(XMLFILE);
+ try {
+ parser.parse();
+ } catch(Exception &e) {
+ goto goonagain;
+ }
+ TEST_TRUE(false, "This test should fail...\n");
}
+goonagain:
+
+unlink(XMLFILE);
+
+TEST_END;
#endif/*TEST_SAXPARSER*/
diff --git a/server/src/semaphore.cc b/server/src/semaphore.cc
new file mode 100644
index 0000000..e5f1f31
--- /dev/null
+++ b/server/src/semaphore.cc
@@ -0,0 +1,47 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * semaphore.cc
+ *
+ * Sat Oct 8 17:44:13 CEST 2005
+ * Copyright 2005 Bent Bisballe Nyeng
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of Pracro.
+ *
+ * Pracro 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 of the License, or
+ * (at your option) any later version.
+ *
+ * Pracro 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 Pracro; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#include "semaphore.h"
+
+Semaphore::Semaphore()
+{
+ sem_init(&semaphore, 0, 0);
+}
+
+Semaphore::~Semaphore()
+{
+ sem_destroy(&semaphore);
+}
+
+void Semaphore::post()
+{
+ sem_post(&semaphore);
+}
+
+void Semaphore::wait()
+{
+ sem_wait(&semaphore);
+}
diff --git a/server/src/semaphore.h b/server/src/semaphore.h
new file mode 100644
index 0000000..72121f9
--- /dev/null
+++ b/server/src/semaphore.h
@@ -0,0 +1,44 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * semaphore.h
+ *
+ * Sat Oct 8 17:44:13 CEST 2005
+ * Copyright 2005 Bent Bisballe Nyeng
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of Pracro.
+ *
+ * Pracro 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 of the License, or
+ * (at your option) any later version.
+ *
+ * Pracro 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 Pracro; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#ifndef __PRACRO_SEMAPHORE_H__
+#define __PRACRO_SEMAPHORE_H__
+
+#include </usr/include/semaphore.h>
+
+class Semaphore {
+public:
+ Semaphore();
+ ~Semaphore();
+
+ void post();
+ void wait();
+
+private:
+ sem_t semaphore;
+};
+
+#endif/*__PRACRO_SEMAPHORE_H__*/
diff --git a/server/src/server.cc b/server/src/server.cc
index 727ac28..1f85479 100644
--- a/server/src/server.cc
+++ b/server/src/server.cc
@@ -26,6 +26,8 @@
*/
#include "server.h"
+#include <config.h>
+
#include "tcpsocket.h"
#include <errno.h>
@@ -36,388 +38,153 @@
#include <unistd.h>
#include <string.h>
+#include <microhttpd.h>
+
#include "configuration.h"
-#include "transaction.h"
-#include "transactionparser.h"
-#include "templateparser.h"
-#include "macroparser.h"
-
-#include "queryhandler.h"
-#include "queryhandlerpracro.h"
-#include "queryhandlerpentominos.h"
-
-#include "luaquerymapper.h"
-#include "database.h"
-#include "widgetgenerator.h"
-#include "resumeparser.h"
-#include "journal_commit.h"
-#include "xml_encode_decode.h"
-
-#include "macrolist.h"
-#include "templatelist.h"
-#include "versionstr.h"
-
-static std::string error_box(std::string message)
+#include "connection.h"
+#include "log.h"
+
+static int handle_request_callback(void *cls,
+ struct MHD_Connection *con,
+ const char *url,
+ const char *method,
+ const char *version,
+ const char *data,
+ unsigned int *data_size,
+ void **con_cls)
{
- std::string errorbox =
- "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
- "<pracro version=\"1.0\">\n"
- " <template name=\"error\">\n"
- " <macro name=\"error\" static=\"true\">\n"
- " <widgets caption=\"ERROR!\" layout=\"vbox\" name=\"error\">\n"
- " <textedit name=\"errorlabel\" value=\"" + message + "\"/>\n"
- " </widgets>\n"
- " </macro>\n"
- " </template>\n"
- "</pracro>\n";
- return errorbox;
-}
+ int ret = MHD_YES;
-class NotFoundException : public Exception {
-public:
- NotFoundException(Request &r)
- : Exception("Macro " + r.macro + " not found in template " + r.templ) {}
-};
+ Connection *connection = (Connection*)*con_cls;
+ PRACRO_DEBUG(httpd, "handle_request_callback con:%p condata:%p\n",
+ con, *con_cls);
-static std::string handleCommits(Transaction *transaction, Database &db,
- JournalWriter &journalwriter, MacroList &macrolist,
- TemplateList &templatelist)
-{
- std::string answer;
+ // Test for new connection
+ if(connection == NULL) {
+ std::string sessionid;
+ const char *sid = MHD_lookup_connection_value(con, MHD_HEADER_KIND,
+ "SessionID");
+ if(sid) sessionid = sid;
- Commits::iterator i = transaction->commits.begin();
- while(i != transaction->commits.end()) {
- Commit &commit = *i;
-
- MacroParser mp(macrolist.getLatestVersion(commit.macro));
- mp.parse();
- Macro *macro = mp.getMacro();
-
- std::string resume = resume_parser(macro->resume, commit);
- commit.fields["journal.resume"] = resume;
- db.commitTransaction(transaction->user, transaction->cpr, *macro, commit.fields);
-
- if(resume != "") {
+ const char *scm = MHD_lookup_connection_value(con, MHD_HEADER_KIND,
+ "SessionCommit");
- TemplateParser tp(templatelist.getLatestVersion(commit.templ));
- tp.parse();
- Template *templ = tp.getTemplate();
+ const char *sdc = MHD_lookup_connection_value(con, MHD_HEADER_KIND,
+ "SessionDiscard");
- journalwriter.addEntry(*transaction, commit, resume, templ);
- }
-
- i++;
+ Environment *env = (Environment *)cls;
+ connection = new Connection(*env, sessionid, scm != NULL, sdc != NULL);
+ *con_cls = connection;
}
- return answer;
-}
-
-
-static std::string handleRequest(Transaction *transaction,
- Database &db,
- JournalWriter &journalwriter,
- MacroList &macrolist,
- TemplateList &templatelist)
-{
- std::string answer;
-
- // Reuse connection throughout entire template.
- QueryHandlerPentominos qh(transaction->cpr);
+ if(!connection) return MHD_NO;
- Requests::iterator i = transaction->requests.begin();
- while(i != transaction->requests.end()) {
- Request &request = *i;
+ if(connection->handle(data, *data_size)) {
+ std::string response = connection->getResponse();
- PRACRO_DEBUG(server, "Handling request - macro: %s, template: %s\n",
- request.macro.c_str(), request.templ.c_str());
-
- // Read and parse the template file.
- TemplateParser tp(templatelist.getLatestVersion(request.templ));
- tp.parse();
+ PRACRO_DEBUG(httpd, "Sending response: [[%s]]\n", response.c_str());
+
+ struct MHD_Response *rsp =
+ MHD_create_response_from_data(response.size(),
+ (void*)response.data(),
+ MHD_NO, // must free
+ MHD_YES); // must copy
- Template *templ = tp.getTemplate();
+ MHD_add_response_header(rsp, MHD_HTTP_HEADER_CONTENT_TYPE,
+ "text/plain; charset=UTF-8");
- answer += " <template name=\"";
- answer += templ->attributes["name"];
- answer += "\" title=\"";
- answer += templ->attributes["title"];
- answer += "\">\n";
+ MHD_add_response_header(rsp, "SessionID",
+ connection->getSessionID().c_str());
- bool foundmacro = false;
+ ret = MHD_queue_response(con, MHD_HTTP_OK, rsp);
+ MHD_destroy_response(rsp);
- // Generate the macro and return it to the client
- std::vector< Macro >::iterator mi2 = templ->macros.begin();
- while(mi2 != templ->macros.end()) {
- Macro &macro = (*mi2);
-
- if(macro.isHeader) {
- answer += " <header caption=\"" + macro.attributes["caption"] + "\"/>\n";
- mi2++;
- continue;
- }
-
- bool completed = db.checkMacro(transaction->cpr,
- macro.attributes["name"],
- time(NULL)-Conf::db_max_ttl);
-
- answer += " <macro completed=";
- if(completed) answer += "\"true\"";
- else answer += "\"false\"";
-
- std::map< std::string, std::string >::iterator ai = macro.attributes.begin();
- while(ai != macro.attributes.end()) {
- std::string name = ai->first;
- std::string value = ai->second;
- answer += " "+name+"=\"" + value + "\"";
- ai++;
- }
-
- if(macro.attributes["name"] == request.macro ||
- (macro.attributes.find("static") != macro.attributes.end() &&
- macro.attributes["static"] == "true")
- ) {
- foundmacro = true;
-
- MacroParser mp(macrolist.getLatestVersion(macro.attributes["name"]));
- mp.parse();
- Macro *m = mp.getMacro();
- answer += " caption=\"" + m->widgets.attributes["caption"] + "\"";
- answer += ">\n";
-
- LUAQueryMapper lqm;
-
- ////////////////////////
- std::vector< Query >::iterator qi = m->queries.begin();
- while(qi != m->queries.end()) {
-
- Query &query = *qi;
- std::string service = query.attributes["service"];
-
- if(service == "pentominos") {
- // Send the queries to Pentominos (if any)
- QueryResult queryresult = qh.exec(*qi);
- lqm.addQueryResult(queryresult);
- }
-
- if(service == "pracro") {
- // Send the queries to Pracro (if any)
- QueryHandlerPracro qh(db, transaction->cpr);
-
- QueryResult queryresult = qh.exec(*qi);
- lqm.addQueryResult(queryresult);
- }
-
- qi++;
- }
-
- // Handle scripts
- if(m->scripts.size()) {
- answer += " <scripts>\n";
-
- std::vector< Script >::iterator spi = m->scripts.begin();
- while(spi != m->scripts.end()) {
- answer += " <script language=\"" + spi->attributes["language"]
- + "\" name=\"" + spi->attributes["name"] + "\">\n";
- answer += xml_encode(spi->attributes["code"]);
- answer += "\n </script>\n";
- spi++;
- }
- answer += " </scripts>\n";
- }
-
- answer += widgetgenerator(transaction->cpr, *m, lqm, db);
- } else {
- // only find macro title
- MacroParser mp(macrolist.getLatestVersion(macro.attributes["name"]));
- mp.parse();
- Macro *m = mp.getMacro();
- answer += " caption=\"" + m->widgets.attributes["caption"] + "\"";
- answer += ">\n";
-
- }
-
- if(completed) {
- answer += " <resume>";
- answer += xml_encode(db.getResume(transaction->cpr, macro, time(NULL) - Conf::db_max_ttl));
- answer += "</resume>\n";
- }
-
- answer += " </macro>\n";
- mi2++;
-
- }
-
- if(foundmacro == false && request.macro != "")
- throw NotFoundException(request);
-
- answer += " </template>\n";
-
- i++;
+ delete connection;
+ *con_cls = NULL;
}
- return answer;
+ *data_size = 0;
+
+ return ret;
}
-static std::string handleTransaction(Transaction *transaction,
- Database &db,
- JournalWriter &journalwriter,
- MacroList &macrolist,
- TemplateList &templatelist)
+void requestCompletedCallback(void *cls,
+ struct MHD_Connection *con,
+ void **con_cls,
+ enum MHD_RequestTerminationCode toe)
{
- std::string answer;
- answer += "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
- answer += "<pracro version=\"1.0\">\n";
-
- try {
- answer += handleCommits(transaction, db, journalwriter, macrolist, templatelist);
- } catch( std::exception &e ) {
- PRACRO_ERR(server, "Commit error: %s\n", e.what());
- return error_box(xml_encode(e.what()));
- }
+ PRACRO_DEBUG(httpd, "requestCompletedCallback %p\n", con);
- try {
- answer += handleRequest(transaction, db, journalwriter,
- macrolist, templatelist);
- } catch( std::exception &e ) {
- PRACRO_ERR(server, "Request error: %s\n", e.what());
- return error_box(xml_encode(e.what()));
+ // If connection was interrupted prematurely delete the content data here.
+ if(*con_cls) {
+ Connection *connection = (Connection*)*con_cls;
+ delete connection;
+ *con_cls = NULL;
}
-
- answer += "</pracro>\n";
-
- PRACRO_DEBUG(server, "Done handling transaction\n");
- PRACRO_DEBUG(serverxml, "%s\n", answer.c_str());
- return answer;
}
-
-static void handleConnection(TCPSocket *socket)
+static void httpderr(void *arg, const char *fmt, va_list ap)
{
- Database db(Conf::database_backend, Conf::database_addr, "", Conf::database_user, Conf::database_passwd, "");
-
- JournalWriter journalwriter(Conf::journal_commit_addr.c_str(), Conf::journal_commit_port);
-
- MacroList macrolist(Conf::xml_basedir + "/macros");
- TemplateList templatelist(Conf::xml_basedir + "/templates");
-
- ssize_t size;
- char buf[4096];
-
- Transaction *transaction = NULL;
- TransactionParser *parser = NULL;
-
- // while( (size = socket->read(buf, sizeof(buf))) != -1) {
- while( (size = socket->read(buf, sizeof(buf))) > 0) {
-
- PRACRO_DEBUG(server, "Read %d bytes from network\n", size);
-
- while(size) {
-
- if(transaction == NULL) {
- transaction = new Transaction();
- }
-
- if(parser == NULL) {
- parser = new TransactionParser(transaction);
- }
-
- PRACRO_DEBUG(server, "Got %d bytes in read loop\n", size);
- if(parser->parse(buf, size)) {
- PRACRO_DEBUG(server, "Got complete XML document %d bytes used, %d bytes in current buffer.\n", parser->usedBytes(), size);
-
- socket->write(handleTransaction(transaction, db, journalwriter,
- macrolist, templatelist));
- size = size - parser->usedBytes();
- if(size) {
- strcpy(buf, buf + parser->usedBytes());
- PRACRO_DEBUG(server, "Replaying %d bytes.\n", size);
- }
-
- delete transaction; transaction = NULL;
- delete parser; parser = NULL;
- } else {
- size = 0;
- memset(buf, 0, sizeof(buf));
- }
- }
- }
-
- if(transaction) {
- delete transaction;
- transaction = NULL;
- }
-
- if(parser) {
- delete parser;
- parser = NULL;
- }
-
- journalwriter.commit();
-
- PRACRO_DEBUG(server, "Out of read loop!\n");
+ PRACRO_ERR_VA(server, fmt, ap);
}
-//#define NON_FORKING
-#include <sys/socket.h>
extern bool pracro_is_running;
void server()
{
+ srand(time(NULL));
+
+ // bool forceshutdown = false;
port_t port = Conf::server_port;
- TCPSocket *socket = NULL;
-
- try {
- socket = new TCPSocket("Listen socket");
- socket->listen(port);
- } catch (Exception &e) {
- PRACRO_ERR_LOG(server, "Error in listen:\n%s\n", e.what());
- delete socket;
- socket = NULL;
+
+ int flags = MHD_USE_DEBUG | MHD_USE_SELECT_INTERNALLY;
+ // | MHD_USE_PEDANTIC_CHECKS
+#ifndef WITHOUT_SSL
+ if(Conf::use_ssl) flags |= MHD_USE_SSL;
+#endif
+
+ PRACRO_DEBUG(server, "Server running on port %d.\n", port);
+
+ Environment env;
+
+ struct MHD_Daemon *d;
+ d = MHD_start_daemon(flags, port, NULL, NULL,
+ handle_request_callback, &env,
+ MHD_OPTION_NOTIFY_COMPLETED,
+ requestCompletedCallback, NULL,
+ MHD_OPTION_CONNECTION_LIMIT, Conf::connection_limit,
+#ifndef WITHOUT_SSL
+ MHD_OPTION_HTTPS_MEM_KEY, Conf::ssl_key.c_str(),
+ MHD_OPTION_HTTPS_MEM_CERT, Conf::ssl_cert.c_str(),
+#endif
+ MHD_OPTION_CONNECTION_TIMEOUT, Conf::connection_timeout,
+ MHD_OPTION_EXTERNAL_LOGGER, httpderr, NULL,
+ MHD_OPTION_END);
+
+ if(!d) {
+ PRACRO_ERR(server, "Failed to initialise MHD_start_daemon!\n");
return;
}
-
- while(pracro_is_running && socket->connected()) {
-
- { // Reload if new port is assigned.
- int old_port = port;
- port = Conf::server_port;
-
- if(port != old_port) {
- // Start listening on the new port
- delete socket;
- socket = new TCPSocket("Listen socket (reloaded)");
- socket->listen(port);
- }
- }
-
- TCPSocket *child = socket->accept();
- if(child) {
-
-#ifndef NON_FORKING
- switch(fork()) {
- case -1: // error
- PRACRO_ERR_LOG(server, "Could not fork: %s\n", strerror(errno));
- break;
-
- case 0: // child
- delete socket;
-#endif/*NON_FORKING*/
- handleConnection(child);
- delete child;
-#ifndef NON_FORKING
- return;
-
- default: // parent
- delete child;
- break;
- }
-#endif/*NON_FORKING*/
-
+ // again:
+ while(pracro_is_running) sleep(1);
+ /*
+ if(!forceshutdown && env.sessions.size() != 0) {
+ char *errbuf;
+ if(asprintf(&errbuf, "There are %d live sessions."
+ " Kill again to force shutdown.\n",
+ env.sessions.size()) != -1) {
+ PRACRO_ERR_LOG(server, "%s", errbuf);
+ log(errbuf);
+ free(errbuf);
}
+ pracro_is_running = true;
+ forceshutdown = true;
+ goto again;
}
+ */
+ env.sessions.store();
- //socket->shutdown();
- delete socket;
+ MHD_stop_daemon(d);
PRACRO_DEBUG(server, "Server gracefully shut down.\n");
}
@@ -439,10 +206,11 @@ char request[] =
int main()
{
Conf::xml_basedir = "../xml/";
- Conf::server_port = 32100; // Make sure wo don't interrupt an already running server.
+ // Make sure wo don't interrupt an already running server.
+ Conf::server_port = 32100;
Conf::database_backend = "testdb";
pid_t pid = fork();
-
+
switch(pid) {
case -1: // error
perror("fork() failed!\n");
diff --git a/server/src/session.cc b/server/src/session.cc
new file mode 100644
index 0000000..803a515
--- /dev/null
+++ b/server/src/session.cc
@@ -0,0 +1,238 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set et sw=2 ts=2: */
+/***************************************************************************
+ * session.cc
+ *
+ * Tue Dec 15 13:36:49 CET 2009
+ * Copyright 2009 Bent Bisballe Nyeng
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of Pracro.
+ *
+ * Pracro 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 of the License, or
+ * (at your option) any later version.
+ *
+ * Pracro 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 Pracro; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#include "session.h"
+
+#include <stdlib.h>
+
+// for stat
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "journalwriter.h"
+#include "configuration.h"
+#include "connectionpool.h"
+#include "sessionserialiser.h"
+
+Session::Session(std::string sessionid)
+{
+ _id = sessionid;
+ _journal = NULL;
+}
+
+Session::~Session()
+{
+ if(_journal) delete _journal;
+}
+
+std::string Session::id()
+{
+ return _id;
+}
+
+void Session::lock()
+{
+ mutex.lock();
+}
+
+void Session::unlock()
+{
+ mutex.unlock();
+}
+
+void Session::commit()
+{
+ if(_journal != NULL) {
+ _journal->commit();
+ delete _journal;
+ _journal = NULL;
+ }
+}
+
+void Session::discard()
+{
+ if(_journal) {
+ delete _journal;
+ _journal = NULL;
+ }
+}
+
+JournalWriter *Session::journal()
+{
+ if(_journal == NULL) {
+ _journal =
+ new JournalWriter(Conf::journal_commit_addr, Conf::journal_commit_port);
+ }
+ return _journal;
+}
+
+Sessions::Sessions()
+{
+}
+
+static bool fexists(const std::string &f)
+{
+ bool ret;
+
+/*
+ struct stat sbuf;
+ int n = stat(f.c_str(), &sbuf);
+ if(n != -1) ret = true;
+ ret = errno != ENOENT;
+*/
+
+ FILE *fp = fopen(f.c_str(), "r");
+ ret = fp != NULL;
+ if(fp) fclose(fp);
+
+ return ret;
+}
+
+Session *Sessions::newSession()
+{
+ char sessionid[32];
+ std::string filename;
+ do {
+ snprintf(sessionid, sizeof(sessionid)-1, "%d", rand());
+ filename = getSessionFilename(Conf::session_path, sessionid);
+ } while(sessions.find(sessionid) != sessions.end() || fexists(filename));
+
+ Session *session = new Session(sessionid);
+ sessions[session->id()] = session;
+ return session;
+}
+
+Session *Sessions::session(std::string sessionid)
+{
+ if(sessions.find(sessionid) != sessions.end())
+ return sessions[sessionid];
+
+ std::string filename = getSessionFilename(Conf::session_path, sessionid);
+ if(fexists(filename)) {
+ Session *s = new Session(sessionid);
+ SessionSerialiser ser(Conf::session_path, s);
+ ser.load();
+ sessions[s->id()] = s;
+
+ fprintf(stderr, "s: %p\n",s);
+
+ return s;
+ }
+
+ return NULL;
+}
+
+Session *Sessions::takeSession(std::string sessionid)
+{
+ Session *s = NULL;
+ if(sessions.find(sessionid) != sessions.end()) {
+ s = sessions[sessionid];
+ }
+
+ if(s) {
+ sessions.erase(sessionid);
+ }
+
+ return s;
+}
+
+void Sessions::deleteSession(std::string sessionid)
+{
+ Session *s = takeSession(sessionid);
+ if(s) delete s;
+}
+
+size_t Sessions::size()
+{
+ return sessions.size();
+}
+
+void Sessions::store()
+{
+ std::map<std::string, Session*>::iterator i = sessions.begin();
+ while(i != sessions.end()) {
+ SessionSerialiser ser(Conf::session_path, i->second);
+ ser.save();
+ delete i->second;
+ sessions.erase(i);
+ i++;
+ }
+ sessions.clear();
+}
+
+SessionAutolock::SessionAutolock(Session &s)
+ : session(s)
+{
+ session.lock();
+}
+
+SessionAutolock::~SessionAutolock()
+{
+ session.unlock();
+}
+
+#ifdef TEST_SESSION
+//deps: configuration.cc journalwriter.cc journal_commit.cc mutex.cc debug.cc sessionserialiser.cc sessionparser.cc saxparser.cc
+//cflags: -I.. $(PTHREAD_CFLAGS) $(EXPAT_CFLAGS)
+//libs: $(PTHREAD_LIBS) $(EXPAT_LIBS)
+#include <test.h>
+
+TEST_BEGIN;
+Sessions sessions;
+
+Conf::session_path = "/tmp";
+
+srand(0); // force seed
+Session *s1 = sessions.newSession();
+srand(0); // force seed
+Session *s2 = sessions.newSession();
+
+TEST_NOTEQUAL(s1->id(), s2->id(), "Testing if IDs are unique.");
+
+TEST_EQUAL(sessions.size(), 2, "Testing if size match.");
+
+std::string sessionid = s1->id();
+SessionSerialiser ser(Conf::session_path, s1);
+ser.save();
+
+sessions.deleteSession(sessionid);
+TEST_EQUAL(sessions.size(), 1, "Testing if size match.");
+
+s1 = sessions.session(sessionid);
+TEST_NOTEQUAL(s1, NULL, "Did we reload the session from disk?");
+
+sessions.store();
+TEST_EQUAL(sessions.size(), 0, "Testing if size match.");
+
+s1 = sessions.session(sessionid);
+TEST_NOTEQUAL(s1, NULL, "Did we reload the session from disk?");
+
+TEST_END;
+
+#endif/*TEST_SESSION*/
diff --git a/server/src/session.h b/server/src/session.h
new file mode 100644
index 0000000..6c614c7
--- /dev/null
+++ b/server/src/session.h
@@ -0,0 +1,109 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set et sw=2 ts=2: */
+/***************************************************************************
+ * session.h
+ *
+ * Tue Dec 15 13:36:49 CET 2009
+ * Copyright 2009 Bent Bisballe Nyeng
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of Pracro.
+ *
+ * Pracro 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 of the License, or
+ * (at your option) any later version.
+ *
+ * Pracro 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 Pracro; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#ifndef __PRACRO_SESSION_H__
+#define __PRACRO_SESSION_H__
+
+#include <string>
+#include <map>
+
+#include "mutex.h"
+
+class JournalWriter;
+
+class Session {
+public:
+ Session(std::string sessionid);
+ ~Session();
+
+ std::string id();
+
+ void lock();
+ void unlock();
+
+ void commit();
+ void discard();
+
+ JournalWriter *journal();
+
+private:
+ JournalWriter *_journal;
+ std::string _id;
+ Mutex mutex;
+};
+
+class Sessions {
+public:
+ Sessions();
+
+ /**
+ * Create a new session, with a unique id. Insert it into the session list,
+ * and return its pointer.
+ */
+ Session *newSession();
+
+ /**
+ * Lookup session in session list. Returns the session or NULL if no session
+ * exists with that sessionid.
+ */
+ Session *session(std::string sessionid);
+
+ /**
+ * Remove session from the session list and return its pointer. It is up to
+ * the caller to delete it.
+ */
+ Session *takeSession(std::string sessionid);
+
+ /**
+ * Remove session from the session list and delete it.
+ */
+ void deleteSession(std::string sessionid);
+
+ /**
+ * Return number of active sessions.
+ */
+ size_t size();
+
+ /**
+ * Write all active sessions to disc.
+ */
+ void store();
+
+private:
+ std::map<std::string, Session *> sessions;
+};
+
+class SessionAutolock {
+public:
+ SessionAutolock(Session &session);
+ ~SessionAutolock();
+
+private:
+ Session &session;
+};
+
+#endif/*__PRACRO_SESSION_H__*/
diff --git a/server/src/sessionparser.cc b/server/src/sessionparser.cc
new file mode 100644
index 0000000..ba3693d
--- /dev/null
+++ b/server/src/sessionparser.cc
@@ -0,0 +1,110 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set et sw=2 ts=2: */
+/***************************************************************************
+ * sessionparser.cc
+ *
+ * Thu May 20 14:30:23 CEST 2010
+ * Copyright 2010 Bent Bisballe Nyeng
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of Pracro.
+ *
+ * Pracro 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 of the License, or
+ * (at your option) any later version.
+ *
+ * Pracro 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 Pracro; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#include "sessionparser.h"
+
+#include "debug.h"
+
+SessionParser::SessionParser()
+{
+ done = false;
+ totalbytes = 0;
+ inresume = false;
+}
+
+SessionParser::~SessionParser()
+{
+}
+
+void SessionParser::characterData(std::string &data)
+{
+ if(inresume) {
+ entries[entries.size()-1].resume += data;
+ }
+}
+
+void SessionParser::startTag(std::string name,
+ std::map<std::string, std::string> attributes)
+{
+ PRACRO_DEBUG(sessionparser, "<%s>\n", name.c_str());
+
+ if(name == "session") {
+ sessionid = attributes["id"];
+ }
+
+ if(name == "journal") {
+ patientid = attributes["patientid"];
+ userid = attributes["userid"];
+ }
+
+ if(name == "entry") {
+ Entry e;
+ e.index = atoi(attributes["index"].c_str());
+ e.macro = attributes["macro"];
+ entries.push_back(e);
+ }
+
+ if(name == "resume") {
+ inresume = true;
+ }
+}
+
+void SessionParser::endTag(std::string name)
+{
+ if(name == "resume") {
+ inresume = false;
+ }
+}
+
+void SessionParser::parseError(const char *buf, size_t len,
+ std::string error, int lineno)
+{
+ PRACRO_ERR(sessionnparser, "SessionParser error at line %d: %s\n",
+ lineno, error.c_str());
+
+ std::string xml;
+ xml.append(buf, len);
+
+ PRACRO_ERR(sessionparser, "\tBuffer %u bytes: [%s]\n",
+ len, xml.c_str());
+
+ throw std::exception();
+}
+
+#ifdef TEST_SESSIONPARSER
+//deps:
+//cflags:
+//libs:
+#include "test.h"
+
+TEST_BEGIN;
+
+#error "Put some testcode here (see test.h for usable macros)."
+
+TEST_END;
+
+#endif/*TEST_SESSIONPARSER*/
diff --git a/server/src/sessionparser.h b/server/src/sessionparser.h
new file mode 100644
index 0000000..37899aa
--- /dev/null
+++ b/server/src/sessionparser.h
@@ -0,0 +1,64 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set et sw=2 ts=2: */
+/***************************************************************************
+ * sessionparser.h
+ *
+ * Thu May 20 14:30:23 CEST 2010
+ * Copyright 2010 Bent Bisballe Nyeng
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of Pracro.
+ *
+ * Pracro 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 of the License, or
+ * (at your option) any later version.
+ *
+ * Pracro 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 Pracro; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#ifndef __PRACRO_SESSIONPARSER_H__
+#define __PRACRO_SESSIONPARSER_H__
+
+#include "saxparser.h"
+
+#include <string>
+#include <vector>
+
+class SessionParser : public SAXParser {
+public:
+ SessionParser();
+ ~SessionParser();
+
+ void characterData(std::string &data);
+ void startTag(std::string name,
+ std::map< std::string, std::string> attributes);
+ void endTag(std::string name);
+ void parseError(const char *buf, size_t len, std::string error, int lineno);
+
+ std::string sessionid;
+ std::string patientid;
+ std::string userid;
+
+ class Entry {
+ public:
+ int index;
+ std::string macro;
+ std::string resume;
+ };
+
+ std::vector<Entry> entries;
+
+private:
+ bool inresume;
+};
+
+#endif/*__PRACRO_SESSIONPARSER_H__*/
diff --git a/server/src/sessionserialiser.cc b/server/src/sessionserialiser.cc
new file mode 100644
index 0000000..10d449d
--- /dev/null
+++ b/server/src/sessionserialiser.cc
@@ -0,0 +1,200 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set et sw=2 ts=2: */
+/***************************************************************************
+ * sessionserialiser.cc
+ *
+ * Thu May 20 11:26:18 CEST 2010
+ * Copyright 2010 Bent Bisballe Nyeng
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of Pracro.
+ *
+ * Pracro 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 of the License, or
+ * (at your option) any later version.
+ *
+ * Pracro 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 Pracro; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#include "sessionserialiser.h"
+
+#include "journalwriter.h"
+
+#include "sessionparser.h"
+
+#include <stdio.h>
+#include <string.h>
+
+std::string getSessionFilename(const std::string &path,
+ const std::string &sessionid)
+{
+ return path + "/pracro_session." + sessionid;
+}
+
+
+static std::string itostr(int i)
+{
+ char sid[32];
+ snprintf(sid, sizeof(sid), "%d", i);
+ return sid;
+}
+
+SessionSerialiser::SessionSerialiser(std::string path, Session *session)
+{
+ this->session = session;
+ this->path = path;
+}
+
+void SessionSerialiser::loadStr(const std::string &xml)
+{
+ // SessionAutolock lock(*session);
+ SessionParser parser;
+ parser.parse(xml.data(), xml.length());
+ JournalWriter *j = session->journal();
+ j->currentuser = parser.userid;
+ j->currentcpr = parser.patientid;
+ std::vector<SessionParser::Entry>::iterator i = parser.entries.begin();
+ while(i != parser.entries.end()) {
+ j->addEntry(i->resume, i->macro, i->index);
+ i++;
+ }
+}
+
+std::string SessionSerialiser::saveStr()
+{
+ // SessionAutolock lock(*session);
+
+ std::string xml;
+
+ xml += "<?xml version='1.0' encoding='UTF-8'?>\n";
+ xml += "<session timestamp=\""+itostr(time(NULL))+"\" "
+ "id=\""+session->id()+"\">\n";
+
+ JournalWriter *journal = session->journal();
+
+ xml += " <journal patientid=\"" + journal->currentcpr +
+ "\" userid=\"" + journal->currentuser + "\">\n";
+
+ std::map< int, JournalWriter::ResumeEntry >::iterator i =
+ journal->entrylist.begin();
+ while(i != journal->entrylist.end()) {
+
+ xml += " <entry index=\""+itostr(i->first) + "\""
+ " macro=\"" + i->second.macro + "\">\n";
+ xml += " <resume>" + i->second.resume + "</resume>\n";
+ xml += " </entry>\n";
+
+ i++;
+ }
+
+ xml += " </journal>\n";
+ xml += "</session>\n";
+
+ return xml;
+}
+
+void SessionSerialiser::load()
+{
+ // read xml from file
+ std::string filename = getSessionFilename(path, session->id());
+
+ FILE *fp = fopen(filename.c_str(), "r");
+ char xml[2048];
+ memset(xml, 0, sizeof(xml));
+ fread(xml, sizeof(xml), 1, fp);
+ fclose(fp);
+
+ loadStr(xml);
+
+ // delete file
+ unlink(filename.c_str());
+
+}
+
+void SessionSerialiser::save()
+{
+ std::string filename = getSessionFilename(path, session->id());
+
+ std::string xml = saveStr();
+
+ // write xml to file
+ FILE *fp = fopen(filename.c_str(), "w");
+ fwrite(xml.data(), xml.size(), 1, fp);
+ fclose(fp);
+}
+
+#ifdef TEST_SESSIONSERIALISER
+//deps: session.cc journalwriter.cc debug.cc configuration.cc mutex.cc journal_commit.cc sessionparser.cc saxparser.cc
+//cflags: -I.. $(PTHREAD_CFLAGS) $(EXPAT_CFLAGS)
+//libs: $(PTHREAD_LIBS) $(EXPAT_LIBS)
+#include "test.h"
+
+#define SID "42"
+#define SPATH "/tmp"
+
+TEST_BEGIN;
+
+std::string xml;
+
+{
+ Session session(SID);
+ JournalWriter *j = session.journal();
+ j->addEntry("some text", "macro1", 0);
+ j->addEntry("some more text", "macro2", 2);
+ j->addEntry("yet some more text", "macro3", 1);
+ SessionSerialiser s(SPATH, &session);
+ xml = s.saveStr();
+ s.loadStr(xml);
+ std::string xml2 = s.saveStr();
+ TEST_EQUAL_STR(xml, xml2, "Compare");
+}
+
+{
+ Session session(SID);
+ JournalWriter *j = session.journal();
+ j->addEntry("some text", "macro1", 0);
+ j->addEntry("some more text", "macro2", 2);
+ j->addEntry("yet some more text", "macro3", 1);
+ SessionSerialiser s(SPATH, &session);
+ xml = s.saveStr();
+}
+
+{
+ Session session(SID);
+ SessionSerialiser s(SPATH, &session);
+ s.loadStr(xml);
+ std::string xml2 = s.saveStr();
+ TEST_EQUAL_STR(xml, xml2, "Compare");
+}
+
+{
+ Session session(SID);
+ JournalWriter *j = session.journal();
+ j->addEntry("some text", "macro1", 0);
+ j->addEntry("some more text", "macro2", 2);
+ j->addEntry("yet some more text", "macro3", 1);
+ SessionSerialiser s(SPATH, &session);
+ s.save();
+}
+
+{
+ Session session(SID);
+ SessionSerialiser s(SPATH, &session);
+ s.load();
+ std::string xml2 = s.saveStr();
+ TEST_EQUAL_STR(xml, xml2, "Compare");
+}
+
+
+TEST_END;
+
+#endif/*TEST_SESSIONSERIALISER*/
diff --git a/server/src/sessionserialiser.h b/server/src/sessionserialiser.h
new file mode 100644
index 0000000..4002760
--- /dev/null
+++ b/server/src/sessionserialiser.h
@@ -0,0 +1,53 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set et sw=2 ts=2: */
+/***************************************************************************
+ * sessionserialiser.h
+ *
+ * Thu May 20 11:26:18 CEST 2010
+ * Copyright 2010 Bent Bisballe Nyeng
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of Pracro.
+ *
+ * Pracro 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 of the License, or
+ * (at your option) any later version.
+ *
+ * Pracro 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 Pracro; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#ifndef __PRACRO_SESSIONSERIALISER_H__
+#define __PRACRO_SESSIONSERIALISER_H__
+
+#include <string>
+
+#include "session.h"
+
+class SessionSerialiser {
+public:
+ SessionSerialiser(std::string path, Session *session);
+
+ void loadStr(const std::string &xml);
+ std::string saveStr();
+
+ void load();
+ void save();
+
+private:
+ Session *session;
+ std::string path;
+};
+
+std::string getSessionFilename(const std::string &path,
+ const std::string &sessionid);
+
+#endif/*__PRACRO_SESSIONSERIALISER_H__*/
diff --git a/server/src/tcpsocket.cc b/server/src/tcpsocket.cc
index 818934e..f748e0a 100644
--- a/server/src/tcpsocket.cc
+++ b/server/src/tcpsocket.cc
@@ -90,14 +90,12 @@ TCPSocket::TCPSocket(std::string name, int sock)
isconnected = false;
this->sock = sock;
- PRACRO_DEBUG(socket, "TCPSocket %s: %p %d (%d)\n", name.c_str(),
- this, sock, getpid());
+ PRACRO_DEBUG(socket, "TCPSocket %s: %p %d (%d)\n", name.c_str(), this, sock, getpid());
}
TCPSocket::~TCPSocket()
{
- PRACRO_DEBUG(socket, "~TCPSocket %s: %p %d (%d)\n", name.c_str(),
- this, sock, getpid());
+ PRACRO_DEBUG(socket, "~TCPSocket %s: %p %d (%d)\n", name.c_str(), this, sock, getpid());
disconnect();
}
@@ -111,7 +109,7 @@ void TCPSocket::listen(unsigned short int port)
if(isconnected) throw TCPListenException("Socket alread connected.");
struct sockaddr_in socketaddr;
- memset((char *) &socketaddr, 0, sizeof(socketaddr));
+ memset((char *) &socketaddr, sizeof(socketaddr), 0);
socketaddr.sin_family = AF_INET;
socketaddr.sin_port = htons(port);
socketaddr.sin_addr.s_addr = htonl(INADDR_ANY);
@@ -161,32 +159,27 @@ TCPSocket *TCPSocket::accept()
}
}
if(FD_ISSET(sock, &fset)) {
- int csock = _accept(sock, (struct sockaddr*)&ssocketaddr,
- (socklen_t*)&csalen);
+ int csock = _accept(sock, (struct sockaddr*)&ssocketaddr, (socklen_t*)&csalen);
TCPSocket *child = new TCPSocket(name + "-child", csock);
if (child->sock == -1) {
- throw TCPAcceptException(std::string("accept failed - ") +
- strerror(errno));
+ throw TCPAcceptException(std::string("accept failed - ") + strerror(errno));
}
child->isconnected = true;
return child;
} else {
- PRACRO_ERR_LOG(socket, "Accept returned with no socket"
- " - This should not happen!\n");
+ PRACRO_ERR_LOG(socket, "Accept returned with no socket - This should not happen!\n");
return NULL;
}
}
-static int _connect(int sockfd, const struct sockaddr *serv_addr,
- socklen_t addrlen)
+static int _connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen)
{return connect(sockfd, serv_addr, addrlen);}
void TCPSocket::connect(std::string addr, unsigned short int port)
throw(TCPConnectException)
{
- if(isconnected)
- throw TCPConnectException("Socket already connected.", "", "");
+ if(isconnected) throw TCPConnectException("Socket already connected.", "", "");
#ifndef BYPASS_STATICALLOCATIONS
// Do DNS lookup
@@ -198,8 +191,7 @@ void TCPSocket::connect(std::string addr, unsigned short int port)
char portno[32];
sprintf(portno, "%d", port);
throw TCPConnectException(addr, portno,
- std::string("host lookup failed: ") +
- hstrerror(h_errno));
+ std::string("host lookup failed: ") + hstrerror(h_errno));
}
addr_list = (struct in_addr **)he->h_addr_list;
@@ -210,7 +202,7 @@ void TCPSocket::connect(std::string addr, unsigned short int port)
#endif/*BYPASS_STATICALLOCATIONS*/
struct sockaddr_in socketaddr;
- memset((char *) &socketaddr, 0, sizeof(socketaddr));
+ memset((char *) &socketaddr, sizeof(socketaddr), 0);
socketaddr.sin_family = AF_INET;
socketaddr.sin_port = htons(port);
socketaddr.sin_addr.s_addr = inet_addr(ip);
@@ -227,8 +219,7 @@ void TCPSocket::connect(std::string addr, unsigned short int port)
void TCPSocket::disconnect()
{
if(sock != -1) {
- PRACRO_DEBUG(socket, "Closing TCPSocket %s: %p %d (%d)\n",
- name.c_str(), this, sock, getpid());
+ PRACRO_DEBUG(socket, "Closing TCPSocket %s: %p %d (%d)\n", name.c_str(), this, sock, getpid());
int ret = close(sock);
if(ret == -1) {
perror(name.c_str());
@@ -305,8 +296,7 @@ int TCPSocket::read(char *buf, int size, long timeout)
return res;
}
-ssize_t _write(int fd, const void *buf, size_t count)
-{ return write(fd, buf, count); }
+ssize_t _write(int fd, const void *buf, size_t count) { return write(fd, buf, count); }
int TCPSocket::write(char *data, int size)
throw(TCPWriteException)
{
diff --git a/server/src/templatelist.cc b/server/src/templatelist.cc
index cdf2b4b..af03586 100644
--- a/server/src/templatelist.cc
+++ b/server/src/templatelist.cc
@@ -27,80 +27,34 @@
*/
#include "templatelist.h"
-#include <sys/types.h>
-#include <dirent.h>
+#include "templateheaderparser.h"
#include "debug.h"
-#include "templateheaderparser.h"
-static std::vector<std::string> listdir(std::string path)
+TemplateList::TemplateList(std::string path)
+ : EntityList(path, "template")
{
- std::vector<std::string> files;
-
- DIR* dir = opendir(path.c_str());
- if(!dir) {
- PRACRO_ERR(dump, "Could not open directory: %s\n", path.c_str());
- return files;
- }
-
- struct dirent *d;
- while((d = readdir(dir)) != 0) {
- //if(d->d_type == DT_DIR) {
- std::string name = d->d_name;
- if(name.length() >= 4 && name.substr(name.length() - 4) == ".xml")
- files.push_back(name);
- //}
- }
- closedir(dir);
-
- return files;
+ rescan();
}
-TemplateList::TemplateList(std::string templatepath)
+void TemplateList::addFile(std::string file)
{
- this->templatepath = templatepath;
- std::vector<std::string> templates = listdir(templatepath);
- std::vector<std::string>::iterator i = templates.begin();
- while(i != templates.end()) {
- TemplateHeaderParser parser(templatepath + "/" + *i);
- try {
- parser.parse();
- Template *templ = parser.getTemplate();
- (*this)[templ->attributes["name"]][VersionStr(templ->attributes["version"])] = *i;
- } catch(Exception &e) {
- PRACRO_WARN(templatelist, "Skipping %s: %s\n", i->c_str(), e.what());
- }
-
- i++;
+ if(file.substr(file.size() - 4) != ".xml") {
+ PRACRO_DEBUG(templatelist, "Skipping file: %s\n", file.c_str());
+ return;
}
- {
- iterator i = begin();
- while(i != end()) {
- TemplateListItem::iterator j = i->second.begin();
- while(j != i->second.end()) {
- PRACRO_DEBUG(templatelist, "%s - v%s file: %s\n",
- i->first.c_str(),
- ((std::string)j->first).c_str(),
- j->second.c_str());
- j++;
- }
- i++;
- }
+ PRACRO_DEBUG(templatelist, "Adding file: %s\n", file.c_str());
+ TemplateHeaderParser parser(file);
+ try {
+ parser.parse();
+ Template *templ = parser.getTemplate();
+ insertEntity(templ->attributes["name"],
+ templ->attributes["version"],
+ file);
+ } catch(Exception &e) {
+ PRACRO_WARN(templatelist, "Skipping %s: %s\n", file.c_str(), e.what());
}
-
-}
-
-std::string TemplateList::getLatestVersion(std::string templ) throw(Exception)
-{
- if(find(templ) == end()) throw Exception("Template ["+templ+"] does not exist");
- TemplateListItem mli = (*this)[templ];
- if(mli.size() == 0) return "";
- PRACRO_DEBUG(templatelist, "Search for %s - found %s v%s\n",
- templ.c_str(),
- (templatepath + "/" + mli.begin()->second).c_str(),
- ((std::string)mli.begin()->first).c_str());
- return templatepath + "/" + mli.begin()->second;
}
#ifdef TEST_TEMPLATELIST
diff --git a/server/src/templatelist.h b/server/src/templatelist.h
index bcf22f1..ce2d1b3 100644
--- a/server/src/templatelist.h
+++ b/server/src/templatelist.h
@@ -28,45 +28,14 @@
#ifndef __PRACRO_TEMPLATELIST_H__
#define __PRACRO_TEMPLATELIST_H__
-#include <map>
-#include <string>
-#include "versionstr.h"
+#include "entitylist.h"
-#include "exception.h"
-
-/**
- * The Items contained in the TemplateList.
- */
-typedef std::map<VersionStr, std::string> TemplateListItem;
-
-/**
- * The TemplateList class is intended for template file caching, so that all templates
- * do not need to be parsed on each template query.
- * It builds a list of templates and versions based on the informations read from
- * the TemplateHeaderParser.
- * This means that just because a template gets into the list doesn't means that it
- * will validate as a correct template (not even nessecarily correct XML).
- */
-class TemplateList : public std::map<std::string, TemplateListItem > {
+class TemplateList : public EntityList {
public:
- /**
- * Constructor.
- * @param templatepath A std::string containing the path in which we should look
- * for xml files.
- */
- TemplateList(std::string templatepath);
-
- /**
- * Convenience method, to gain the filename of the latest version of a given template.
- * This method throws an Exception if the template does not exist in the tree.
- * @param template A std::string containing the name of the wanted template.
- * @return A std::string containing the file containing the template with full path
- * included.
- */
- std::string getLatestVersion(std::string templ) throw(Exception);
+ TemplateList(std::string path);
private:
- std::string templatepath;
+ void addFile(std::string file);
};
#endif/*__PRACRO_TEMPLATELIST_H__*/
diff --git a/server/src/transactionhandler.cc b/server/src/transactionhandler.cc
new file mode 100644
index 0000000..c9c58b6
--- /dev/null
+++ b/server/src/transactionhandler.cc
@@ -0,0 +1,287 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set et sw=2 ts=2: */
+/***************************************************************************
+ * transactionhandler.cc
+ *
+ * Fri Dec 18 10:00:50 CET 2009
+ * Copyright 2009 Bent Bisballe Nyeng
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of Pracro.
+ *
+ * Pracro 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 of the License, or
+ * (at your option) any later version.
+ *
+ * Pracro 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 Pracro; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#include "transactionhandler.h"
+
+#include "macroparser.h"
+#include "resumeparser.h"
+#include "templateparser.h"
+#include "configuration.h"
+#include "luaquerymapper.h"
+#include "queryhandlerpentominos.h"
+#include "queryhandlerpracro.h"
+#include "xml_encode_decode.h"
+#include "widgetgenerator.h"
+#include "journalwriter.h"
+
+static std::string error_box(std::string message)
+{
+ std::string errorbox =
+ "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<pracro version=\"1.0\">\n"
+ " <error>" + message + "</error>\n"
+ "</pracro>\n";
+ return errorbox;
+}
+
+static std::string handleCommits(Transaction &transaction, Environment &env,
+ Session &session)
+{
+ std::string answer;
+
+ if(transaction.commits.size() > 0) {
+ AutoBorrower<Database*> borrower(env.dbpool);
+ Database *db = borrower.get();
+
+ Commits::iterator i = transaction.commits.begin();
+ while(i != transaction.commits.end()) {
+ Commit &commit = *i;
+
+ MacroParser mp(env.macrolist.getLatestVersion(commit.macro));
+ mp.parse();
+ Macro *macro = mp.getMacro();
+
+ std::string resume = resume_parser(macro->resume, commit);
+ commit.fields["journal.resume"] = resume;
+ db->commitTransaction(transaction.user, transaction.cpr, *macro,
+ commit.fields);
+
+ if(resume != "") {
+
+ TemplateParser tp(env.templatelist.getLatestVersion(commit.templ));
+ tp.parse();
+ Template *templ = tp.getTemplate();
+
+ session.journal()->addEntry(transaction, commit, resume, templ);
+ }
+
+ i++;
+ }
+ }
+
+ return answer;
+}
+
+static std::string handleRequest(Transaction &transaction, Environment &env,
+ Session &session)
+{
+ std::string answer;
+
+ if(transaction.requests.size() > 0) {
+
+ AutoBorrower<Database*> borrower(env.dbpool);
+ Database *db = borrower.get();
+
+ Requests::iterator i = transaction.requests.begin();
+ while(i != transaction.requests.end()) {
+ Request &request = *i;
+
+ PRACRO_DEBUG(server, "Handling request - macro: %s, template: %s\n",
+ request.macro.c_str(), request.templ.c_str());
+
+ // Read and parse the template file.
+ TemplateParser tp(env.templatelist.getLatestVersion(request.templ));
+ tp.parse();
+
+ Template *templ = tp.getTemplate();
+
+ answer += " <template name=\"";
+ answer += templ->attributes["name"];
+ answer += "\" title=\"";
+ answer += templ->attributes["title"];
+ answer += "\">\n";
+
+ bool foundmacro = false;
+
+ // Generate the macro and return it to the client
+ std::vector< Macro >::iterator mi2 = templ->macros.begin();
+ while(mi2 != templ->macros.end()) {
+ Macro &macro = (*mi2);
+
+ if(macro.isHeader) {
+ answer += " <header caption=\"" + macro.attributes["caption"] +
+ "\"/>\n";
+ mi2++;
+ continue;
+ }
+
+ bool completed = db->checkMacro(transaction.cpr,
+ macro.attributes["name"],
+ time(NULL)-Conf::db_max_ttl);
+
+ answer += " <macro uid=\"42\" completed=";
+ if(completed) answer += "\"true\"";
+ else answer += "\"false\"";
+
+ std::map< std::string, std::string >::iterator ai =
+ macro.attributes.begin();
+ while(ai != macro.attributes.end()) {
+ std::string name = ai->first;
+ std::string value = ai->second;
+ answer += " "+name+"=\"" + value + "\"";
+ ai++;
+ }
+
+ if(macro.attributes["name"] == request.macro ||
+ (macro.attributes.find("static") != macro.attributes.end() &&
+ macro.attributes["static"] == "true")
+ ) {
+ foundmacro = true;
+
+ MacroParser mp(env.macrolist.getLatestVersion(macro.attributes["name"]));
+ mp.parse();
+ Macro *m = mp.getMacro();
+ answer += " caption=\"" + m->widgets.attributes["caption"] + "\"";
+ answer += ">\n";
+
+ AutoBorrower<Artefact*> borrower(env.atfpool);
+ Artefact *atf = borrower.get();
+
+ LUAQueryMapper lqm;
+
+ ////////////////////////
+ std::vector< Query >::iterator qi = m->queries.begin();
+ while(qi != m->queries.end()) {
+
+ Query &query = *qi;
+ std::string service = query.attributes["service"];
+
+ if(service == "pentominos") {
+ // Send the queries to Pentominos (if any)
+ QueryHandlerPentominos qh(*atf, transaction.cpr,
+ "pracrod"/*user*/);
+
+ QueryResult queryresult = qh.exec(*qi);
+ lqm.addQueryResult(queryresult);
+ }
+
+ if(service == "pracro") {
+ // Send the queries to Pentominos (if any)
+ QueryHandlerPracro qh(*db, transaction.cpr);
+
+ QueryResult queryresult = qh.exec(*qi);
+ lqm.addQueryResult(queryresult);
+ }
+
+ qi++;
+ }
+
+ // Handle scripts
+ if(m->scripts.size()) {
+ answer += " <scripts>\n";
+
+ std::vector< Script >::iterator spi = m->scripts.begin();
+ while(spi != m->scripts.end()) {
+ answer += " <script language=\"" +
+ spi->attributes["language"]
+ + "\" name=\"" + spi->attributes["name"] + "\">\n";
+ answer += xml_encode(spi->attributes["code"]);
+ answer += "\n </script>\n";
+ spi++;
+ }
+ answer += " </scripts>\n";
+ }
+
+ answer += widgetgenerator(transaction.cpr, *m, lqm, *db);
+ } else {
+ // only find macro title
+ MacroParser mp(env.macrolist.getLatestVersion(macro.attributes["name"]));
+ mp.parse();
+ Macro *m = mp.getMacro();
+ answer += " caption=\"" + m->widgets.attributes["caption"] + "\"";
+ answer += ">\n";
+
+ }
+
+ if(completed) {
+ answer += " <resume>";
+ answer += xml_encode(db->getResume(transaction.cpr,
+ macro,
+ time(NULL) - Conf::db_max_ttl));
+ answer += "</resume>\n";
+ }
+
+ answer += " </macro>\n";
+ mi2++;
+
+ }
+
+ if(foundmacro == false && request.macro != "")
+ throw NotFoundException(request);
+
+ answer += " </template>\n";
+
+ i++;
+ }
+ }
+
+ return answer;
+}
+
+std::string handleTransaction(Transaction &transaction, Environment &env,
+ Session &session)
+{
+ std::string answer;
+
+ answer += "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
+ answer += "<pracro version=\"1.0\">\n";
+
+ try {
+ answer += handleCommits(transaction, env, session);
+ } catch( std::exception &e ) {
+ PRACRO_ERR(server, "Commit error: %s\n", e.what());
+ return error_box(xml_encode(e.what()));
+ }
+
+ try {
+ answer += handleRequest(transaction, env, session);
+ } catch( std::exception &e ) {
+ PRACRO_ERR(server, "Request error: %s\n", e.what());
+ return error_box(xml_encode(e.what()));
+ }
+
+ answer += "</pracro>\n";
+
+ PRACRO_DEBUG(server, "Done handling transaction\n");
+ PRACRO_DEBUG(serverxml, "%s\n", answer.c_str());
+
+ return answer;
+}
+
+#ifdef TEST_TRANSACTIONHANDLER
+//deps:
+//cflags: -I..
+//libs:
+#include "test.h"
+
+TEST_BEGIN;
+
+#error TODO: Put some testcode here (see test.h for usable macros).
+
+TEST_END;
+
+#endif/*TEST_TRANSACTIONHANDLER*/
diff --git a/server/src/transactionhandler.h b/server/src/transactionhandler.h
new file mode 100644
index 0000000..ae1857c
--- /dev/null
+++ b/server/src/transactionhandler.h
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set et sw=2 ts=2: */
+/***************************************************************************
+ * transactionhandler.h
+ *
+ * Fri Dec 18 10:00:50 CET 2009
+ * Copyright 2009 Bent Bisballe Nyeng
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of Pracro.
+ *
+ * Pracro 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 of the License, or
+ * (at your option) any later version.
+ *
+ * Pracro 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 Pracro; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#ifndef __PRACRO_TRANSACTIONHANDLER_H__
+#define __PRACRO_TRANSACTIONHANDLER_H__
+
+#include "transaction.h"
+#include "session.h"
+#include "environment.h"
+
+#include "exception.h"
+
+class NotFoundException : public Exception {
+public:
+ NotFoundException(Request &r)
+ : Exception("Macro " + r.macro + " not found in template " + r.templ) {}
+};
+
+std::string handleTransaction(Transaction &transaction, Environment &env, Session &session);
+
+#endif/*__PRACRO_TRANSACTIONHANDLER_H__*/
diff --git a/server/src/transactionparser.cc b/server/src/transactionparser.cc
index f1f79c6..b33cac6 100644
--- a/server/src/transactionparser.cc
+++ b/server/src/transactionparser.cc
@@ -36,31 +36,6 @@
#include "debug.h"
#include "exception.h"
-static void error(const char* fmt, ...)
-{
- PRACRO_ERR_LOG(transactionparser, "Error in TransactionParser: ");
-
- {
- va_list argp;
- va_start(argp, fmt);
- PRACRO_ERR_LOG_VA(macro, fmt, argp);
- va_end(argp);
-
- fprintf(stderr, "\n");
- }
-
- {
- char *p;
- va_list argp;
- va_start(argp, fmt);
- if(vasprintf(&p, fmt, argp) != -1) {
- throw Exception("Error in TransactionParser: " + std::string(p));
- free(p);
- }
- va_end(argp);
- }
-}
-
TransactionParser::TransactionParser(Transaction *transaction)
{
this->transaction = transaction;
@@ -68,8 +43,11 @@ TransactionParser::TransactionParser(Transaction *transaction)
totalbytes = 0;
}
-void TransactionParser::startTag(std::string name, std::map< std::string, std::string> attributes)
+void TransactionParser::startTag(std::string name,
+ std::map<std::string, std::string> attributes)
{
+ PRACRO_DEBUG(transactionparser, "<%s>\n", name.c_str());
+
if(name == "pracro") {
transaction->user = attributes["user"];
transaction->cpr = attributes["cpr"];
@@ -92,29 +70,46 @@ void TransactionParser::startTag(std::string name, std::map< std::string, std::s
}
if(name == "field") {
- if(!transaction->commits.size()) error("Field without a commit tag!");
- if(attributes.find("name") == attributes.end()) error("Field is missing 'name' attribute");
- if(attributes.find("value") == attributes.end()) error("Field is missing 'value' attribute");
- transaction->commits.back().fields[attributes["name"]] = attributes["value"];
+ if(!transaction->commits.size()) {
+ PRACRO_ERR(transactionparser, "Field without a commit tag!");
+ throw std::exception();
+ }
+
+ if(attributes.find("name") == attributes.end()) {
+ PRACRO_ERR(transactionparser, "Field is missing 'name' attribute");
+ throw std::exception();
+ }
+
+ if(attributes.find("value") == attributes.end()) {
+ PRACRO_ERR(transactionparser, "Field is missing 'value' attribute");
+ throw std::exception();
+ }
+
+ transaction->commits.back().fields[attributes["name"]] =
+ attributes["value"];
}
}
-void TransactionParser::parseError(const char *buf, size_t len, std::string error, int lineno)
+void TransactionParser::parseError(const char *buf, size_t len,
+ std::string error, int lineno)
{
- PRACRO_ERR_LOG(transactionparser, "TransactionParser error at line %d: %s\n",
- lineno, error.c_str());
- PRACRO_ERR_LOG(transactionparser, "\tBuffer %u bytes: [", len);
- if(fwrite(buf, len, 1, stderr) != len) {}
- PRACRO_ERR_LOG(transactionparser, "]\n");
-
- char *slineno;
- if(asprintf(&slineno, " at line %d\n", lineno) != -1) {
- throw Exception(error + slineno);
- free(slineno);
- }
+ PRACRO_ERR(transactionparser, "TransactionParser error at line %d: %s\n",
+ lineno, error.c_str());
+
+ std::string xml;
+ xml.append(buf, len);
+
+ PRACRO_ERR(transactionparser, "\tBuffer %u bytes: [%s]\n",
+ len, xml.c_str());
+
+ throw std::exception();
}
#ifdef TEST_TRANSACTIONPARSER
+//deps: saxparser.cc debug.cc exception.cc log.cc
+//cflags: -I.. $(EXPAT_CFLAGS)
+//libs: $(EXPAT_LIBS)
+#include "test.h"
static char xml_minimal[] =
"<?xml version='1.0' encoding='UTF-8'?>\n"
@@ -146,53 +141,36 @@ static char xml_fail[] =
"</pracro>\n"
;
-int main()
-{
- // Test minimal
- try {
- Transaction transaction;
- TransactionParser parser(&transaction);
- parser.parse(xml_minimal, strlen(xml_minimal));
- } catch(Exception &e) {
- printf("ERROR: %s\n", e.what());
- return 1;
- }
+TEST_BEGIN;
- // Test request
- try {
- Transaction transaction;
- TransactionParser parser(&transaction);
- parser.parse(xml_request, strlen(xml_request));
- } catch(Exception &e) {
- printf("ERROR: %s\n", e.what());
- return 1;
- }
-
- // Test commit
- try {
- Transaction transaction;
- TransactionParser parser(&transaction);
- parser.parse(xml_commit, strlen(xml_commit));
- } catch(Exception &e) {
- printf("ERROR: %s\n", e.what());
- return 1;
- }
+// Test minimal
+{
+ Transaction transaction;
+ TransactionParser parser(&transaction);
+ TEST_NOEXCEPTION(parser.parse(xml_minimal, sizeof(xml_minimal)-1), "minimal");
+}
- // Test parse error (should throw an exception)
- try {
- Transaction transaction;
- TransactionParser parser(&transaction);
- parser.parse(xml_fail, strlen(xml_fail));
- } catch(Exception &e) {
- printf("ERROR: %s\n", e.what());
- goto onandon;
- }
- printf("We should fail here...\n");
- return 1;
+// Test request
+{
+ Transaction transaction;
+ TransactionParser parser(&transaction);
+ TEST_NOEXCEPTION(parser.parse(xml_request, sizeof(xml_request)-1), "request");
+}
- onandon:
+// Test commit
+{
+ Transaction transaction;
+ TransactionParser parser(&transaction);
+ TEST_NOEXCEPTION(parser.parse(xml_commit, sizeof(xml_commit)-1), "commit");
+}
- return 0;
+// Test parse error (should throw an exception)
+{
+ Transaction transaction;
+ TransactionParser parser(&transaction);
+ TEST_EXCEPTION(parser.parse(xml_fail, sizeof(xml_fail)-1), std::exception, "parse error");
}
+TEST_END;
+
#endif/*TEST_TRANSACTIONPARSER*/
diff --git a/server/src/widgetgenerator.cc b/server/src/widgetgenerator.cc
index 9fdacd2..425c71e 100644
--- a/server/src/widgetgenerator.cc
+++ b/server/src/widgetgenerator.cc
@@ -40,8 +40,7 @@ static std::string automap(std::string name)
if(name[i] == '.') groupcheck += " and " + group;
else groupcheck += name[i];
}
- groupcheck += " and " + name + ".value and " + name +
- ".timestamp and " + name + ".source";
+ groupcheck += " and " + name + ".value and " + name + ".timestamp and " + name + ".source";
groupcheck += ")\n";
std::string automapstring =
@@ -74,12 +73,9 @@ static std::string send_macro_widget(Macro &macro,
std::string prefilled;
time_t timestamp = 0;
time_t now = time(NULL);
- /*
- if(widget.attributes.find("value") != widget.attributes.end()) {
- widget.attributes["value"] = "";
- }
- */
+
result = tabs + "<" + widget.attributes["tagname"];
+ std::map< std::string, std::string >::iterator p = widget.attributes.begin();
PRACRO_DEBUG(prefill, "%s: %s\n",
widget.attributes["tagname"].c_str(),
@@ -113,9 +109,9 @@ static std::string send_macro_widget(Macro &macro,
if(luamap != "") {
Value value = mapper.map(luamap);
if(value.timestamp > now - Conf::pentominos_max_ttl) {
- widget.attributes["value"] = xml_encode(value.value);
+ widget.attributes["value"] = value.value;
timestamp = value.timestamp;
- prefilled = xml_encode(value.source);
+ prefilled = value.source;
}
PRACRO_DEBUG(prefill, "map: (%s, %d)\n",
@@ -141,8 +137,7 @@ static std::string send_macro_widget(Macro &macro,
if(values[widget.attributes["name"]].timestamp > timestamp) {
if(values[widget.attributes["name"]].timestamp > now - Conf::db_max_ttl) {
- widget.attributes["value"] =
- xml_encode(values[widget.attributes["name"]].value);
+ widget.attributes["value"] = values[widget.attributes["name"]].value;
timestamp = values[widget.attributes["name"]].timestamp;
prefilled = "pracro";
}
@@ -154,7 +149,6 @@ static std::string send_macro_widget(Macro &macro,
widget.attributes["value"].c_str(),
(int)timestamp);
- std::map< std::string, std::string >::iterator p = widget.attributes.begin();
while(p != widget.attributes.end()) {
if(p->first != "tagname" && p->first != "map") {
if( ! (p->first == "name" && p->second == "") )
@@ -184,12 +178,9 @@ static std::string send_macro_widget(Macro &macro,
static void get_fields(Widget &widget, Fieldnames &fields)
{
- // if(widget.attributes.find("value") != widget.attributes.end()) {
- if(widget.attributes.find("name") != widget.attributes.end()) {
- if(widget.attributes["name"] != "")
- fields.push_back(widget.attributes["name"]);
+ if(widget.attributes.find("value") != widget.attributes.end()) {
+ if(widget.attributes["name"] != "") fields.push_back(widget.attributes["name"]);
}
- // }
std::vector< Widget >::iterator w = widget.widgets.begin();
while(w != widget.widgets.end()) {
@@ -198,8 +189,7 @@ static void get_fields(Widget &widget, Fieldnames &fields)
}
}
-std::string widgetgenerator(std::string cpr, Macro &macro,
- LUAQueryMapper &mapper, Database &db)
+std::string widgetgenerator(std::string cpr, Macro &macro, LUAQueryMapper &mapper, Database &db)
{
Fieldnames fields;
get_fields(macro.widgets, fields);
diff --git a/server/xml/macros/cycloplegisk_refraktion-1.0.xml b/server/xml/macros/cycloplegisk_refraktion-1.0.xml
index 7c66cf3..cdef363 100644
--- a/server/xml/macros/cycloplegisk_refraktion-1.0.xml
+++ b/server/xml/macros/cycloplegisk_refraktion-1.0.xml
@@ -35,7 +35,7 @@
return out
</resume>
<queries>
- <query service="pentominos" class="visutron900plus" ttl="100000"/>
+ <query class="cycloplegisk_refraktion" ttl="100000"/>
<query service="pracro" class="missing_eye_odxt" ttl="1000000"/>
<query service="pracro" class="missing_eye_osin" ttl="1000000"/>
</queries>
@@ -76,102 +76,6 @@
end
return value, timestamp, source
</map>
- <map name="visutron900plus.osin.sph_near">
- -- Returning 0, 0 invalidates the result
- value = 0
- timestamp = 0
- source = 0
-
- if(visutron900plus and visutron900plus.osin and visutron900plus.osin.sph_near and visutron900plus.osin.sph_near.value and visutron900plus.osin.sph_near.timestamp)
- then
- value = visutron900plus.osin.sph_near.value
- -- convert . to ,
- value = string.gsub(value, '[.]', ',')
- timestamp = visutron900plus.osin.sph_near.timestamp
- source = visutron900plus.osin.sph_near.source
- end
- return value, timestamp, source
- </map>
- <map name="visutron900plus.osin.cyl">
- -- Returning 0, 0 invalidates the result
- value = 0
- timestamp = 0
- source = 0
-
- if(visutron900plus and visutron900plus.osin and visutron900plus.osin.cyl and visutron900plus.osin.cyl.value and visutron900plus.osin.cyl.timestamp)
- then
- value = visutron900plus.osin.cyl.value
- -- convert . to ,
- value = string.gsub(value, '[.]', ',')
- timestamp = visutron900plus.osin.cyl.timestamp
- source = visutron900plus.osin.cyl.source
- end
- return value, timestamp, source
- </map>
- <map name="visutron900plus.osin.axis">
- -- Returning 0, 0 invalidates the result
- value = 0
- timestamp = 0
- source = 0
-
- if(visutron900plus and visutron900plus.osin and visutron900plus.osin.axis and visutron900plus.osin.axis.value and visutron900plus.osin.axis.timestamp)
- then
- value = visutron900plus.osin.axis.value
- -- convert . to ,
- value = string.gsub(value, '[.]', ',')
- timestamp = visutron900plus.osin.axis.timestamp
- source = visutron900plus.osin.axis.source
- end
- return value, timestamp, source
- </map>
- <map name="visutron900plus.odxt.sph_near">
- -- Returning 0, 0 invalidates the result
- value = 0
- timestamp = 0
- source = 0
-
- if(visutron900plus and visutron900plus.odxt and visutron900plus.odxt.sph_near and visutron900plus.odxt.sph_near.value and visutron900plus.odxt.sph_near.timestamp)
- then
- value = visutron900plus.odxt.sph_near.value
- -- convert . to ,
- value = string.gsub(value, '[.]', ',')
- timestamp = visutron900plus.odxt.sph_near.timestamp
- source = visutron900plus.odxt.sph_near.source
- end
- return value, timestamp, source
- </map>
- <map name="visutron900plus.odxt.cyl">
- -- Returning 0, 0 invalidates the result
- value = 0
- timestamp = 0
- source = 0
-
- if(visutron900plus and visutron900plus.odxt and visutron900plus.odxt.cyl and visutron900plus.odxt.cyl.value and visutron900plus.odxt.cyl.timestamp)
- then
- value = visutron900plus.odxt.cyl.value
- -- convert . to ,
- value = string.gsub(value, '[.]', ',')
- timestamp = visutron900plus.odxt.cyl.timestamp
- source = visutron900plus.odxt.cyl.source
- end
- return value, timestamp, source
- </map>
- <map name="visutron900plus.odxt.axis">
- -- Returning 0, 0 invalidates the result
- value = 0
- timestamp = 0
- source = 0
-
- if(visutron900plus and visutron900plus.odxt and visutron900plus.odxt.axis and visutron900plus.odxt.axis.value and visutron900plus.odxt.axis.timestamp)
- then
- value = visutron900plus.odxt.axis.value
- -- convert . to ,
- value = string.gsub(value, '[.]', ',')
- timestamp = visutron900plus.odxt.axis.timestamp
- source = visutron900plus.odxt.axis.source
- end
- return value, timestamp, source
- </map>
</maps>
<scripts>
<script language="lua" name="lt20gt-25">
@@ -250,17 +154,17 @@
<frame layout="vbox">
<label caption="Sf:"/>
- <lineedit name="cycloplegisk_refraktion.sf.odxt" map="visutron900plus.odxt.sph_near"
+ <lineedit name="cycloplegisk_refraktion.sf.odxt" map="cycloplegisk_refraktion.sf.odxt"
regexp="[+-]{0,1}\d{1,2},\d{2}" script="lt20gt-25" value=""/>
</frame>
<frame layout="vbox">
<label caption="Cyl:"/>
- <lineedit name="cycloplegisk_refraktion.cyl.odxt" map="visutron900plus.odxt.cyl"
+ <lineedit name="cycloplegisk_refraktion.cyl.odxt" map="cycloplegisk_refraktion.cyl.odxt"
regexp="|[+-]{0,1}\d{1,2},\d{2}" script="lt10gt-15" value=""/>
</frame>
<frame layout="vbox">
<label caption="Grader:"/>
- <lineedit name="cycloplegisk_refraktion.grader.odxt" map="visutron900plus.odxt.axis"
+ <lineedit name="cycloplegisk_refraktion.grader.odxt" map="cycloplegisk_refraktion.grader.odxt"
regexp="|[\d]+" script="lt359gt0" value=""/>
</frame>
</frame>
@@ -276,17 +180,17 @@
<frame layout="vbox">
<label caption="Sf:"/>
- <lineedit name="cycloplegisk_refraktion.sf.osin" map="visutron900plus.osin.sph_near"
+ <lineedit name="cycloplegisk_refraktion.sf.osin" map="cycloplegisk_refraktion.sf.osin"
regexp="[+-]{0,1}\d{1,2},\d{2}" script="lt20gt-25" value=""/>
</frame>
<frame layout="vbox">
<label caption="Cyl:"/>
- <lineedit name="cycloplegisk_refraktion.cyl.osin" map="visutron900plus.osin.cyl"
+ <lineedit name="cycloplegisk_refraktion.cyl.osin" map="cycloplegisk_refraktion.cyl.osin"
regexp="|[+-]{0,1}\d{1,2},\d{2}" script="lt10gt-15" value=""/>
</frame>
<frame layout="vbox">
<label caption="Grader:"/>
- <lineedit name="cycloplegisk_refraktion.grader.osin" map="visutron900plus.osin.axis"
+ <lineedit name="cycloplegisk_refraktion.grader.osin" map="cycloplegisk_refraktion.grader.osin"
regexp="|[\d]+" script="lt359gt0" value=""/>
</frame>
</frame>
diff --git a/server/xml/macros/egen_brille-1.0.xml b/server/xml/macros/egen_brille-1.0.xml
index 89cfef2..14df7db 100644
--- a/server/xml/macros/egen_brille-1.0.xml
+++ b/server/xml/macros/egen_brille-1.0.xml
@@ -35,7 +35,7 @@
return out
</resume>
<queries>
-<!-- <query service="pentominos" class="lensmeter" ttl="100000"/> -->
+ <query class="lensmeter" ttl="100000"/>
<query service="pracro" class="missing_eye_odxt" ttl="1000000"/>
<query service="pracro" class="missing_eye_osin" ttl="1000000"/>
</queries>
diff --git a/server/xml/macros/manifest_refraktion-1.0.xml b/server/xml/macros/manifest_refraktion-1.0.xml
index f057435..46b6f35 100644
--- a/server/xml/macros/manifest_refraktion-1.0.xml
+++ b/server/xml/macros/manifest_refraktion-1.0.xml
@@ -35,7 +35,7 @@
return out
</resume>
<queries>
- <query service="pentominos" class="phoroptor" ttl="100000"/>
+ <query class="manifest_refraktion" ttl="100000"/>
<query service="pracro" class="missing_eye_odxt" ttl="1000000"/>
<query service="pracro" class="missing_eye_osin" ttl="1000000"/>
</queries>
@@ -76,102 +76,6 @@
end
return value, timestamp, source
</map>
- <map name="phoroptor.osin.sph">
- -- Returning 0, 0 invalidates the result
- value = 0
- timestamp = 0
- source = 0
-
- if(phoroptor and phoroptor.osin and phoroptor.osin.sph and phoroptor.osin.sph.value and phoroptor.osin.sph.timestamp)
- then
- value = phoroptor.osin.sph.value
- -- convert . to ,
- value = string.gsub(value, '[.]', ',')
- timestamp = phoroptor.osin.sph.timestamp
- source = phoroptor.osin.sph.source
- end
- return value, timestamp, source
- </map>
- <map name="phoroptor.osin.cyl">
- -- Returning 0, 0 invalidates the result
- value = 0
- timestamp = 0
- source = 0
-
- if(phoroptor and phoroptor.osin and phoroptor.osin.cyl and phoroptor.osin.cyl.value and phoroptor.osin.cyl.timestamp)
- then
- value = phoroptor.osin.cyl.value
- -- convert . to ,
- value = string.gsub(value, '[.]', ',')
- timestamp = phoroptor.osin.cyl.timestamp
- source = phoroptor.osin.cyl.source
- end
- return value, timestamp, source
- </map>
- <map name="phoroptor.osin.axis">
- -- Returning 0, 0 invalidates the result
- value = 0
- timestamp = 0
- source = 0
-
- if(phoroptor and phoroptor.osin and phoroptor.osin.axis and phoroptor.osin.axis.value and phoroptor.osin.axis.timestamp)
- then
- value = phoroptor.osin.axis.value
- -- convert . to ,
- value = string.gsub(value, '[.]', ',')
- timestamp = phoroptor.osin.axis.timestamp
- source = phoroptor.osin.axis.source
- end
- return value, timestamp, source
- </map>
- <map name="phoroptor.odxt.sph">
- -- Returning 0, 0 invalidates the result
- value = 0
- timestamp = 0
- source = 0
-
- if(phoroptor and phoroptor.odxt and phoroptor.odxt.sph and phoroptor.odxt.sph.value and phoroptor.odxt.sph.timestamp)
- then
- value = phoroptor.odxt.sph.value
- -- convert . to ,
- value = string.gsub(value, '[.]', ',')
- timestamp = phoroptor.odxt.sph.timestamp
- source = phoroptor.odxt.sph.source
- end
- return value, timestamp, source
- </map>
- <map name="phoroptor.odxt.cyl">
- -- Returning 0, 0 invalidates the result
- value = 0
- timestamp = 0
- source = 0
-
- if(phoroptor and phoroptor.odxt and phoroptor.odxt.cyl and phoroptor.odxt.cyl.value and phoroptor.odxt.cyl.timestamp)
- then
- value = phoroptor.odxt.cyl.value
- -- convert . to ,
- value = string.gsub(value, '[.]', ',')
- timestamp = phoroptor.odxt.cyl.timestamp
- source = phoroptor.odxt.cyl.source
- end
- return value, timestamp, source
- </map>
- <map name="phoroptor.odxt.axis">
- -- Returning 0, 0 invalidates the result
- value = 0
- timestamp = 0
- source = 0
-
- if(phoroptor and phoroptor.odxt and phoroptor.odxt.axis and phoroptor.odxt.axis.value and phoroptor.odxt.axis.timestamp)
- then
- value = phoroptor.odxt.axis.value
- -- convert . to ,
- value = string.gsub(value, '[.]', ',')
- timestamp = phoroptor.odxt.axis.timestamp
- source = phoroptor.odxt.axis.source
- end
- return value, timestamp, source
- </map>
</maps>
<scripts>
<script language="lua" name="lt20gt-25">
@@ -258,17 +162,17 @@
<frame layout="hbox">
<frame layout="vbox">
<label caption="Sf:"/>
- <lineedit name="manifest_refraktion.sf.odxt" map="phoroptor.sph.odxt"
+ <lineedit name="manifest_refraktion.sf.odxt" map="manifest_refraktion.sf.odxt"
regexp="[+-]{0,1}\d{1,2},\d{2}" script="lt20gt-25" value=""/>
</frame>
<frame layout="vbox">
<label caption="Cyl:"/>
- <lineedit name="manifest_refraktion.cyl.odxt" map="phoroptor.cyl.odxt"
+ <lineedit name="manifest_refraktion.cyl.odxt" map="manifest_refraktion.cyl.odxt"
regexp="|[+-]{0,1}\d{1,2},\d{2}" script="lt10gt-15" value=""/>
</frame>
<frame layout="vbox">
<label caption="Grader:"/>
- <lineedit name="manifest_refraktion.grader.odxt" map="phoroptor.axis.odxt"
+ <lineedit name="manifest_refraktion.grader.odxt" map="manifest_refraktion.grader.odxt"
regexp="|[\d]+" script="lt359gt0" value=""/>
</frame>
</frame>
@@ -286,17 +190,17 @@
<frame layout="hbox">
<frame layout="vbox">
<label caption="Sf:"/>
- <lineedit name="manifest_refraktion.sf.osin" map="phoroptor.sph.osin"
+ <lineedit name="manifest_refraktion.sf.osin" map="manifest_refraktion.sf.osin"
regexp="[+-]{0,1}\d{1,2},\d{2}" script="lt20gt-25" value=""/>
</frame>
<frame layout="vbox">
<label caption="Cyl:"/>
- <lineedit name="manifest_refraktion.cyl.osin" map="phoroptor.cyl.osin"
+ <lineedit name="manifest_refraktion.cyl.osin" map="manifest_refraktion.cyl.osin"
regexp="|[+-]{0,1}\d{1,2},\d{2}" script="lt10gt-15" value=""/>
</frame>
<frame layout="vbox">
<label caption="Grader:"/>
- <lineedit name="manifest_refraktion.grader.osin" map="phoroptor.axis.osin"
+ <lineedit name="manifest_refraktion.grader.osin" map="manifest_refraktion.grader.osin"
regexp="|[\d]+" script="lt359gt0" value=""/>
</frame>
</frame>
diff --git a/server/xml/macros/ref-spaltelampe-1.0.xml b/server/xml/macros/ref-spaltelampe-1.0.xml
index c7ce659..95866fe 100644
--- a/server/xml/macros/ref-spaltelampe-1.0.xml
+++ b/server/xml/macros/ref-spaltelampe-1.0.xml
@@ -52,66 +52,10 @@
out = out .. getValue('spaltelampe.epitel.andet.odxt') .. '\n'
end
- if ( getValue('spaltelampe.stroma.klart.odxt') ~= '' or getValue('spaltelampe.stroma.karindvaekst.odxt') ~= '' or getValue('spaltelampe.stroma.makulering.odxt') ~= '' or getValue('spaltelampe.stroma.mdfolder.odxt') ~= '' or getValue('spaltelampe.stroma.andet.odxt') ~= '' or getValue('spaltelampe.stroma.haze.odxt') ~= '' )
- then
- out = out .. ' Stroma: '
- if ( getValue('spaltelampe.stroma.klart.odxt') ~= '' )
- then
- out = out .. getValue('spaltelampe.stroma.klart.odxt')
- if ( getValue('spaltelampe.stroma.karindvaekst.odxt') ~= '' or getValue('spaltelampe.stroma.makulering.odxt') ~= '' or getValue('spaltelampe.stroma.mdfolder.odxt') ~= '' or getValue('spaltelampe.stroma.andet.odxt') ~= '' or getValue('spaltelampe.stroma.haze.odxt') ~= '' )
- then
- out = out .. ', '
- else
- out = out .. '\n'
- end
- end
- if ( getValue('spaltelampe.stroma.karindvaekst.odxt') ~= '' )
- then
- out = out .. getValue('spaltelampe.stroma.karindvaekst.odxt')
- if ( getValue('spaltelampe.stroma.makulering.odxt') ~= '' or getValue('spaltelampe.stroma.mdfolder.odxt') ~= '' or getValue('spaltelampe.stroma.andet.odxt') ~= '' or getValue('spaltelampe.stroma.haze.odxt') ~= '' )
- then
- out = out .. ', '
- else
- out = out .. '\n'
- end
- end
- if ( getValue('spaltelampe.stroma.makulering.odxt') ~= '' )
- then
- out = out .. getValue('spaltelampe.stroma.makulering.odxt')
- if ( getValue('spaltelampe.stroma.mdfolder.odxt') ~= '' or getValue('spaltelampe.stroma.andet.odxt') ~= '' or getValue('spaltelampe.stroma.haze.odxt') ~= '' )
- then
- out = out .. ', '
- else
- out = out .. '\n'
- end
- end
- if ( getValue('spaltelampe.stroma.mdfolder.odxt') ~= '' )
- then
- out = out .. getValue('spaltelampe.stroma.mdfolder.odxt')
- if ( getValue('spaltelampe.stroma.andet.odxt') ~= '' or getValue('spaltelampe.stroma.haze.odxt') ~= '' )
- then
- out = out .. ', '
- else
- out = out .. '\n'
- end
- end
- if ( getValue('spaltelampe.stroma.haze.odxt') ~= '' )
- then
- out = out .. getValue('spaltelampe.stroma.haze.odxt')
- if ( getValue('spaltelampe.stroma.andet.odxt') ~= '' )
- then
- out = out .. ', '
- else
- out = out .. '\n'
- end
- end
- if ( getValue('spaltelampe.stroma.andet.odxt') ~= '' )
- then
- out = out .. getValue('spaltelampe.stroma.andet.odxt')
- out = out .. '\n'
- end
+ if ( getValue('spaltelampe.stroma.odxt') ~= '' )
+ then
+ out = out .. ' Stroma: ' .. getValue('spaltelampe.stroma.odxt') .. '\n'
end
-
if ( getValue('spaltelampe.flap.odxt') ~= '' )
then
out = out .. ' Flap: ' .. getValue('spaltelampe.flap.odxt') .. '\n'
@@ -210,67 +154,10 @@
then
out = out .. ' Epitel: ' .. getValue('spaltelampe.epitel.osin') .. '\n'
end
-
- if ( getValue('spaltelampe.stroma.klart.osin') ~= '' or getValue('spaltelampe.stroma.karindvaekst.osin') ~= '' or getValue('spaltelampe.stroma.makulering.osin') ~= '' or getValue('spaltelampe.stroma.mdfolder.osin') ~= '' or getValue('spaltelampe.stroma.andet.osin') ~= '' or getValue('spaltelampe.stroma.haze.osin') ~= '' )
- then
- out = out .. ' Stroma: '
- if ( getValue('spaltelampe.stroma.klart.osin') ~= '' )
- then
- out = out .. getValue('spaltelampe.stroma.klart.osin')
- if ( getValue('spaltelampe.stroma.karindvaekst.osin') ~= '' or getValue('spaltelampe.stroma.makulering.osin') ~= '' or getValue('spaltelampe.stroma.mdfolder.osin') ~= '' or getValue('spaltelampe.stroma.andet.osin') ~= '' or getValue('spaltelampe.stroma.haze.osin') ~= '' )
- then
- out = out .. ', '
- else
- out = out .. '\n'
- end
- end
- if ( getValue('spaltelampe.stroma.karindvaekst.osin') ~= '' )
- then
- out = out .. getValue('spaltelampe.stroma.karindvaekst.osin')
- if ( getValue('spaltelampe.stroma.makulering.osin') ~= '' or getValue('spaltelampe.stroma.mdfolder.osin') ~= '' or getValue('spaltelampe.stroma.andet.osin') ~= '' or getValue('spaltelampe.stroma.haze.osin') ~= '' )
- then
- out = out .. ', '
- else
- out = out .. '\n'
- end
- end
- if ( getValue('spaltelampe.stroma.makulering.osin') ~= '' )
- then
- out = out .. getValue('spaltelampe.stroma.makulering.osin')
- if ( getValue('spaltelampe.stroma.mdfolder.osin') ~= '' or getValue('spaltelampe.stroma.andet.osin') ~= '' or getValue('spaltelampe.stroma.haze.osin') ~= '' )
- then
- out = out .. ', '
- else
- out = out .. '\n'
- end
- end
- if ( getValue('spaltelampe.stroma.mdfolder.osin') ~= '' )
- then
- out = out .. getValue('spaltelampe.stroma.mdfolder.osin')
- if ( getValue('spaltelampe.stroma.andet.osin') ~= '' or getValue('spaltelampe.stroma.haze.osin') ~= '' )
- then
- out = out .. ', '
- else
- out = out .. '\n'
- end
- end
- if ( getValue('spaltelampe.stroma.haze.osin') ~= '' )
- then
- out = out .. getValue('spaltelampe.stroma.haze.osin')
- if ( getValue('spaltelampe.stroma.andet.osin') ~= '' )
- then
- out = out .. ', '
- else
- out = out .. '\n'
- end
- end
- if ( getValue('spaltelampe.stroma.andet.osin') ~= '' )
- then
- out = out .. getValue('spaltelampe.stroma.andet.osin')
- out = out .. '\n'
- end
+ if ( getValue('spaltelampe.stroma.osin') ~= '' )
+ then
+ out = out .. ' Stroma: ' .. getValue('spaltelampe.stroma.osin') .. '\n'
end
-
if ( getValue('spaltelampe.flap.osin') ~= '' )
then
out = out .. ' Flap: ' .. getValue('spaltelampe.flap.osin') .. '\n'
@@ -434,31 +321,24 @@
<frame layout="vbox">
<label caption="Stroma:"/>
<label/>
- <label/>
- <label/>
- <label/>
</frame>
<frame layout="vbox">
- <checkbox name="spaltelampe.stroma.klart.odxt" caption="Klart" falsevalue="" truevalue="Klart"/>
- <checkbox name="spaltelampe.stroma.karindvaekst.odxt" caption="Karindvækst" falsevalue="" truevalue="Karindvækst"/>
- <checkbox name="spaltelampe.stroma.makulering.odxt" caption="Makulering" falsevalue="" truevalue="Makulering"/>
- <checkbox name="spaltelampe.stroma.mdfolder.odxt" caption="MD-folder" falsevalue="" truevalue="MD-folder"/>
- <frame layout="hbox">
- <label caption="Haze:"/>
- <combobox name="spaltelampe.stroma.haze.odxt" layout="vbox" value="">
- <item caption="Ingen" value=""/>
- <item caption="Spor af haze - grad 0,5" value="Spor af haze - grad 0,5"/>
- <item caption="Let haze - grad 1" value="Let haze - grad 1"/>
- <item caption="Nogen haze - grad 2" value="Nogen haze - grad 2"/>
- <item caption="Udtalt haze - grad 3" value="Udtalt haze - grad 3"/>
- <item caption="Massiv haze - grad 4" value="Massiv haze - grad 4"/>
- </combobox>
- <spacer/>
- </frame>
- <frame layout="hbox">
- <label caption="Andet:"/>
- <lineedit name="spaltelampe.stroma.andet.odxt"/>
- </frame>
+ <altcombobox name="spaltelampe.stroma.odxt" layout="vbox" value="Klart">
+ <item caption="Ikke udfyldt" value=""/>
+ <item caption="Klart" value="Klart"/>
+ <item caption="Karindvækst" value="Karindvækst"/>
+ <item caption="Makulering" value="Makulering"/>
+ <item caption="MD-folder" value="MD-folder"/>
+ <item caption="Spor af haze - grad 0,5" value="Spor af haze - grad 0,5"/>
+ <item caption="Let haze - grad 1" value="Let haze - grad 1"/>
+ <item caption="Nogen haze - grad 2" value="Nogen haze - grad 2"/>
+ <item caption="Udtalt haze - grad 3" value="Udtalt haze - grad 3"/>
+ <item caption="Massiv haze - grad 4" value="Massiv haze - grad 4"/>
+ <altitem caption="Andet" value="andet" layout="hbox" innerwidget="spaltelampe.stroma.andet.odxt">
+ <label caption="Andet:"/>
+ <lineedit name="spaltelampe.stroma.andet.odxt"/>
+ </altitem>
+ </altcombobox>
</frame>
</frame>
@@ -631,31 +511,24 @@
<frame layout="vbox">
<label caption="Stroma:"/>
<label/>
- <label/>
- <label/>
- <label/>
</frame>
<frame layout="vbox">
- <checkbox name="spaltelampe.stroma.klart.osin" caption="Klart" falsevalue="" truevalue="Klart"/>
- <checkbox name="spaltelampe.stroma.karindvaekst.osin" caption="Karindvækst" falsevalue="" truevalue="Karindvækst"/>
- <checkbox name="spaltelampe.stroma.makulering.osin" caption="Makulering" falsevalue="" truevalue="Makulering"/>
- <checkbox name="spaltelampe.stroma.mdfolder.osin" caption="MD-folder" falsevalue="" truevalue="MD-folder"/>
- <frame layout="hbox">
- <label caption="Haze:"/>
- <combobox name="spaltelampe.stroma.haze.osin" layout="vbox" value="">
- <item caption="Ingen" value=""/>
- <item caption="Spor af haze - grad 0,5" value="Spor af haze - grad 0,5"/>
- <item caption="Let haze - grad 1" value="Let haze - grad 1"/>
- <item caption="Nogen haze - grad 2" value="Nogen haze - grad 2"/>
- <item caption="Udtalt haze - grad 3" value="Udtalt haze - grad 3"/>
- <item caption="Massiv haze - grad 4" value="Massiv haze - grad 4"/>
- </combobox>
- <spacer/>
- </frame>
- <frame layout="hbox">
- <label caption="Andet:"/>
- <lineedit name="spaltelampe.stroma.andet.osin"/>
- </frame>
+ <altcombobox name="spaltelampe.stroma.osin" layout="vbox" value="Klart">
+ <item caption="Ikke udfyldt" value=""/>
+ <item caption="Klart" value="Klart"/>
+ <item caption="Karindvækst" value="Karindvækst"/>
+ <item caption="Makulering" value="Makulering"/>
+ <item caption="MD-folder" value="MD-folder"/>
+ <item caption="Spor af haze - grad 0,5" value="Spor af haze - grad 0,5"/>
+ <item caption="Let haze - grad 1" value="Let haze - grad 1"/>
+ <item caption="Nogen haze - grad 2" value="Nogen haze - grad 2"/>
+ <item caption="Udtalt haze - grad 3" value="Udtalt haze - grad 3"/>
+ <item caption="Massiv haze - grad 4" value="Massiv haze - grad 4"/>
+ <altitem caption="Andet" value="andet" layout="hbox" innerwidget="spaltelampe.stroma.andet.osin">
+ <label caption="Andet:"/>
+ <lineedit name="spaltelampe.stroma.andet.osin"/>
+ </altitem>
+ </altcombobox>
</frame>
</frame>
@@ -705,26 +578,26 @@
<label/>
</frame>
<frame layout="vbox">
- <altcombobox name="spaltelampe.interface.partikler.osin" layout="vbox" value="">
+ <altcombobox name="spaltelampe.partikler.osin" layout="vbox" value="">
<item caption="Ej relevant" value=""/>
<item caption="Ingen partikler eller debris" value="Ingen partikler eller debris"/>
<item caption="Enkelte partikler" value="Enkelte partikler"/>
<item caption="Nogen partikler" value="Nogen partikler"/>
<item caption="Udtalte partikler" value="Udtalte partikler"/>
- <altitem caption="Andet" value="andet" layout="hbox" innerwidget="spaltelampe.interface.partikler.andet.osin">
+ <altitem caption="Andet" value="andet" layout="hbox" innerwidget="spaltelampe.partikler.andet.osin">
<label caption="Andet:"/>
- <lineedit name="spaltelampe.interface.partikler.andet.osin"/>
+ <lineedit name="spaltelampe.partikler.andet.osin"/>
</altitem>
</altcombobox>
- <altcombobox name="spaltelampe.interface.epitelindvaekst.osin" layout="vbox" value="">
+ <altcombobox name="spaltelampe.epitelindvaekst.osin" layout="vbox" value="">
<item caption="Ej relevant" value=""/>
<item caption="Ingen epitelindvækst" value="Ingen epitelindvækst"/>
<item caption="Diskret epitelindvækst" value="Diskret epitelindvækst"/>
<item caption="Let epitelindvækst" value="Let epitelindvækst"/>
<item caption="Betydende epitelindvækst" value="Betydende epitelindvækst"/>
- <altitem caption="Andet" value="andet" layout="hbox" innerwidget="spaltelampe.interface.epitelindvaekst.andet.osin">
+ <altitem caption="Andet" value="andet" layout="hbox" innerwidget="spaltelampe.epitelindvaekst.andet.osin">
<label caption="Andet:"/>
- <lineedit name="spaltelampe.interface.epitelindvaekst.andet.osin"/>
+ <lineedit name="spaltelampe.epitelindvaekst.andet.osin"/>
</altitem>
</altcombobox>
</frame>
diff --git a/server/xml/macros/ref_90d_linse-1.0.xml b/server/xml/macros/ref_90d_linse-1.0.xml
index 5fb7cfb..059958b 100644
--- a/server/xml/macros/ref_90d_linse-1.0.xml
+++ b/server/xml/macros/ref_90d_linse-1.0.xml
@@ -215,7 +215,7 @@
</altcombobox>
<frame name="hul_eller_rift.frame.odxt" layout="hbox">
<label caption="Hul eller rift kl.:"/>
- <combobox name="90d_linse.hul_eller_rift_kl.odxt">
+ <combobox name="90_dlinse.hul_eller_rift_kl.odxt">
<item caption="1" value="1"/>
<item caption="2" value="2"/>
<item caption="3" value="3"/>
diff --git a/server/xml/macros/ref_aktuelle-1.0.xml b/server/xml/macros/ref_aktuelle-1.0.xml
index 8421ca1..2fc4d4f 100644
--- a/server/xml/macros/ref_aktuelle-1.0.xml
+++ b/server/xml/macros/ref_aktuelle-1.0.xml
@@ -22,8 +22,7 @@
<frame layout="vbox">
<label caption="Patienten benytter:"/>
<combobox name="ref_aktuelle.bruger_nu" layout="vbox">
- <item caption="Ingen korrektion" value="ingen korrektion"/>
- <item caption="Briller" value="briller"/>
+ <item caption="Briller" value="Briller"/>
<item caption="Hårde kontaktlinser" value="hårde kontaktlinser"/>
<item caption="Bløde kontaktlinser" value="bløde kontaktlinser"/>
<item caption="Både briller og kontaktlinser" value="både briller og kontaktlinser"/>
diff --git a/server/xml/macros/ref_behandling-kirurgisk_procedure-1.0.xml b/server/xml/macros/ref_behandling-kirurgisk_procedure-1.0.xml
index faa7355..a35e2c8 100644
--- a/server/xml/macros/ref_behandling-kirurgisk_procedure-1.0.xml
+++ b/server/xml/macros/ref_behandling-kirurgisk_procedure-1.0.xml
@@ -2,25 +2,19 @@
<macro name="ref_behandling.kirurgisk_procedure" version="1.0">
<resume language="lua">
out = ''
-
out = out .. 'I Oxybuprokain dråbeanæstesi foretages ' .. getValue('ref_behandling.kirurgisk_procedure.type') .. ' på ' .. getValue('ref_behandling.kirurgisk_procedure.oeje') .. ' øje.\n'
-
-
if ( getValue('ref_behandling.kirurgisk_procedure.type') == 'LASIK' )
then
out = out .. 'LASIK flappen skæres med ' .. getValue('ref_behandling.kirurgisk_procedure.lasik.metode') .. '.\n'
- if ( getValue('ref_behandling.kirurgisk_procedure.lasik.metode') == 'Moria M2 90 SU' or getValue('ref_behandling.kirurgisk_procedure.lasik.metode') == 'Moria M2 130' )
- then
- out = out .. ' Variabel sugekop: ' .. getValue('ref_behandling.kirurgisk_procedure.lasik.sugekop') .. '\n'
- out = out .. ' Variabel hængsel: ' .. getValue('ref_behandling.kirurgisk_procedure.lasik.haengsel') .. '\n'
- end
- if ( getValue('ref_behandling.kirurgisk_procedure.lasik.metode') == 'Visumax' )
+
+ if ( getValue('ref_behandling.kirurgisk_procedure.lasik.metode') == 'femtosekundlaser' )
then
- out = out .. ' Flapdiameter: ' .. getValue('ref_behandling.kirurgisk_procedure.lasik.flapdiameter') .. ' mm\n'
- out = out .. ' Flaptykkelse: ' .. getValue('ref_behandling.kirurgisk_procedure.lasik.flaptykkelse') .. ' um\n'
- out = out .. ' Kantprofil: ' .. getValue('ref_behandling.kirurgisk_procedure.lasik.kantprofil') .. '\n'
+ out = out .. 'Flapdiameter: ' .. getValue('ref_behandling.kirurgisk_procedure.lasik.flapdiameter') .. ' mm\n'
+ out = out .. 'Flaptykkelse: ' .. getValue('ref_behandling.kirurgisk_procedure.lasik.flaptykkelse') .. ' um\n'
+ out = out .. 'Kantprofil: ' .. getValue('ref_behandling.kirurgisk_procedure.lasik.kantprofil') .. '\n'
end
+
out = out .. 'Flappen løftes med flap-lifter.\n\n'
end
@@ -44,41 +38,11 @@
out = out .. getValue('ref_behandling.kirurgisk_procedure.lasek.part1') .. '\n\n'
end
- if ( getValue('ref_behandling.kirurgisk_procedure.type') == 'FLEX' )
- then
- out = out .. 'FLEX flappen skæres med ' .. getValue('ref_behandling.kirurgisk_procedure.flex.metode') .. '.\n'
-
- if ( getValue('ref_behandling.kirurgisk_procedure.flex.metode') == 'Moria M2 90 SU' or getValue('ref_behandling.kirurgisk_procedure.flex.metode') == 'Moria M2 130' )
- then
- out = out .. ' Variabel sugekop: ' .. getValue('ref_behandling.kirurgisk_procedure.flex.sugekop') .. '\n'
- out = out .. ' Variabel hængsel: ' .. getValue('ref_behandling.kirurgisk_procedure.flex.haengsel') .. '\n'
- end
-
- if ( getValue('ref_behandling.kirurgisk_procedure.flex.metode') == 'Visumax' )
- then
- out = out .. ' Flapdiameter: ' .. getValue('ref_behandling.kirurgisk_procedure.flex.flapdiameter') .. ' mm\n'
- out = out .. ' Flaptykkelse: ' .. getValue('ref_behandling.kirurgisk_procedure.flex.flaptykkelse') .. ' um\n'
- out = out .. ' Kantprofil: ' .. getValue('ref_behandling.kirurgisk_procedure.flex.kantprofil') .. '\n'
- end
-
- out = out .. 'Flappen løftes med flap-lifter.\n\n'
- end
-
-
-
- out = out .. 'Tilstræbt refraktionsændring:\n'
- out = out .. 'Algoritme: ' .. getValue('ref_behandling.kirurgisk_procedure.tilstraebtrefraktionsaendring.algoritme') .. '\n'
- out = out .. 'Korrektion: ' .. getValue('ref_behandling.kirurgisk_procedure.tilstraebtrefraktionsaendring.sf') .. ' sf ' .. getValue('ref_behandling.kirurgisk_procedure.tilstraebtrefraktionsaendring.cyl') .. ' x ' .. getValue('ref_behandling.kirurgisk_procedure.tilstraebtrefraktionsaendring.grader') .. '\n'
- out = out .. 'Behandlingsdiameter: ' .. getValue('ref_behandling.kirurgisk_procedure.tilstraebtrefraktionsaendring.behandlingsdiameter') .. ' mm\n'
- out = out .. 'Behandlingsdybde: ' .. getValue('ref_behandling.kirurgisk_procedure.tilstraebtrefraktionsaendring.behandlingsdybde') .. ' um\n'
- if ( getValue('ref_behandling.kirurgisk_procedure.tilstraebtrefraktionsaendring.algoritme') == 'FLEX' )
- then
- out = out .. 'Kanttykkelse: ' .. getValue('ref_behandling.kirurgisk_procedure.tilstraebtrefraktionsaendring.kanttykkelse') .. ' mym\n\n'
- else
- out = out .. '\n'
- end
-
-
+ out = out .. 'Fotoablation:\n'
+ out = out .. 'Algoritme: ' .. getValue('ref_behandling.kirurgisk_procedure.fotoablation.algoritme') .. '\n'
+ out = out .. 'Korrektion: ' .. getValue('ref_behandling.kirurgisk_procedure.fotoablation.sf') .. ' sf ' .. getValue('ref_behandling.kirurgisk_procedure.fotoablation.cyl') .. ' x ' .. getValue('ref_behandling.kirurgisk_procedure.fotoablation.grader') .. '\n'
+ out = out .. 'Ablationsdiameter: ' .. getValue('ref_behandling.kirurgisk_procedure.fotoablation.ablationsdiameter') .. ' mm\n'
+ out = out .. 'Ablationsdybde: ' .. getValue('ref_behandling.kirurgisk_procedure.fotoablation.ablationsdybde') .. ' um\n\n'
if ( getValue('ref_behandling.kirurgisk_procedure.type') == 'LASIK' )
then
@@ -105,17 +69,8 @@
out = out .. getValue('ref_behandling.kirurgisk_procedure.lasek.part2') .. '\n\n'
end
- if ( getValue('ref_behandling.kirurgisk_procedure.type') == 'FLEX' )
- then
- out = out .. getValue('ref_behandling.kirurgisk_procedure.flex.part2') .. '\n\n'
- end
-
-
-
out = out .. 'Der dryppes med ' .. getValue('ref_behandling.kirurgisk_procedure.drypperegime') .. '\n\n'
-
-
if ( getValue('ref_behandling.kirurgisk_procedure.komplikationer') ~= '' )
then
out = out .. 'Komplikationer: ' .. getValue('ref_behandling.kirurgisk_procedure.komplikationer')
@@ -135,12 +90,10 @@
disable('prk_frame1')
disable('relasik_frame1')
disable('lasek_frame1')
- disable('flex_frame1')
enable('lasik_frame2')
disable('prk_frame2')
disable('relasik_frame2')
disable('lasek_frame2')
- disable('flex_frame2')
end
if ( getValue('ref_behandling.kirurgisk_procedure.type') == 'PRK' )
then
@@ -148,12 +101,10 @@
enable('prk_frame1')
disable('relasik_frame1')
disable('lasek_frame1')
- disable('flex_frame1')
disable('lasik_frame2')
enable('prk_frame2')
disable('relasik_frame2')
disable('lasek_frame2')
- disable('flex_frame2')
end
if ( getValue('ref_behandling.kirurgisk_procedure.type') == 'reLASIK' )
then
@@ -161,12 +112,10 @@
disable('prk_frame1')
enable('relasik_frame1')
disable('lasek_frame1')
- disable('flex_frame1')
disable('lasik_frame2')
disable('prk_frame2')
enable('relasik_frame2')
disable('lasek_frame2')
- disable('flex_frame2')
end
if ( getValue('ref_behandling.kirurgisk_procedure.type') == 'rePRK' )
then
@@ -174,12 +123,10 @@
enable('prk_frame1')
disable('relasik_frame1')
disable('lasek_frame1')
- disable('flex_frame1')
disable('lasik_frame2')
enable('prk_frame2')
disable('relasik_frame2')
disable('lasek_frame2')
- disable('flex_frame2')
end
if ( getValue('ref_behandling.kirurgisk_procedure.type') == 'LASEK' )
then
@@ -187,60 +134,19 @@
disable('prk_frame1')
disable('relasik_frame1')
enable('lasek_frame1')
- disable('flex_frame1')
disable('lasik_frame2')
disable('prk_frame2')
disable('relasik_frame2')
enable('lasek_frame2')
- disable('flex_frame2')
- end
- if ( getValue('ref_behandling.kirurgisk_procedure.type') == 'FLEX' )
- then
- disable('lasik_frame1')
- disable('prk_frame1')
- disable('relasik_frame1')
- disable('lasek_frame1')
- enable('flex_frame1')
- disable('lasik_frame2')
- disable('prk_frame2')
- disable('relasik_frame2')
- disable('lasek_frame2')
- enable('flex_frame2')
- end
- return true
- </script>
- <script language="lua" name="lasik_metode_check">
- disable('lasik_visumax')
- disable('lasik_moria')
- if ( getValue('ref_behandling.kirurgisk_procedure.lasik.metode') == 'Visumax' )
- then
- enable('lasik_visumax')
- end
- if ( getValue('ref_behandling.kirurgisk_procedure.lasik.metode') == 'Moria M2 90 SU' or getValue('ref_behandling.kirurgisk_procedure.lasik.metode') == 'Moria M2 130' )
- then
- enable('lasik_moria')
end
return true
</script>
- <script language="lua" name="flex_metode_check">
- disable('flex_visumax')
- disable('flex_moria')
- if ( getValue('ref_behandling.kirurgisk_procedure.flex.metode') == 'Visumax' )
+ <script language="lua" name="femtosekundlaser_check">
+ if ( getValue('ref_behandling.kirurgisk_procedure.lasik.metode') == 'femtosekundlaser' )
then
- enable('flex_visumax')
- end
- if ( getValue('ref_behandling.kirurgisk_procedure.flex.metode') == 'Moria M2 90 SU' or getValue('ref_behandling.kirurgisk_procedure.flex.metode') == 'Moria M2 130' )
- then
- enable('flex_moria')
- end
- return true
- </script>
- <script language="lua" name="algoritme">
- if ( getValue('ref_behandling.kirurgisk_procedure.tilstraebtrefraktionsaendring.algoritme') == 'FLEX' )
- then
- enable('flex_algoritme')
+ enable('femtosekundlaser')
else
- disable('flex_algoritme')
+ disable('femtosekundlaser')
end
return true
</script>
@@ -374,12 +280,11 @@
<item caption="reLASIK" value="reLASIK"/>
<item caption="rePRK" value="rePRK"/>
<item caption="LASEK" value="LASEK"/>
- <item caption="FLEX" value="FLEX"/>
</combobox>
<label caption="på"/>
<combobox name="ref_behandling.kirurgisk_procedure.oeje" value="">
- <item caption="Højre" value="højre"/>
- <item caption="Venstre" value="venstre"/>
+ <item caption="højre" value="højre"/>
+ <item caption="venstre" value="venstre"/>
</combobox>
<label caption="øje"/>
<spacer/>
@@ -392,41 +297,20 @@
<!-- LASIK frame -->
<frame name="lasik_frame1" caption="LASIK" layout="vbox">
<label caption="LASIK flappen skæres med:"/>
- <altcombobox name="ref_behandling.kirurgisk_procedure.lasik.metode" value="" layout="vbox" script="lasik_metode_check">
+ <altcombobox name="ref_behandling.kirurgisk_procedure.lasik.metode" value="" layout="vbox" script="femtosekundlaser_check">
<item caption="Ikke udfyldt" value=""/>
<item caption="Moria M2 90 SU" value="Moria M2 90 SU"/>
<item caption="Moria M2 130" value="Moria M2 130"/>
- <item caption="Visumax" value="Visumax"/>
+ <item caption="femtosekundlaser" value="femtosekundlaser"/>
<altitem caption="Andet" value="andet" innerwidget="lasik_andet" layout="hbox">
<label caption="Andet:"/>
- <lineedit name="lasik_andet"/>
+ <lineedit name="lasik_andet" regexp="[0-9]+(,\d+|\d*)"/>
</altitem>
</altcombobox>
- <frame name="lasik_moria" layout="vbox">
- <frame layout="hbox">
- <label caption="Variabel sugekop:"/>
- <combobox name="ref_behandling.kirurgisk_procedure.lasik.sugekop" value="" layout="vbox">
- <item caption="-1" value="-1"/>
- <item caption="0" value="0"/>
- <item caption="+1" value="+1"/>
- <item caption="+2" value="+2"/>
- </combobox>
- <spacer/>
- </frame>
- <frame layout="hbox">
- <label caption="Variabel hængsel:"/>
- <combobox name="ref_behandling.kirurgisk_procedure.lasik.haengsel" value="" layout="vbox">
- <item caption="7,5" value="7,5"/>
- <item caption="8,0" value="8,0"/>
- <item caption="8,5" value="8,5"/>
- </combobox>
- <spacer/>
- </frame>
- </frame>
- <frame name="lasik_visumax" layout="vbox">
+ <frame name="femtosekundlaser" layout="vbox">
<frame layout="hbox">
<label caption="Flapdiameter:"/>
- <lineedit name="ref_behandling.kirurgisk_procedure.lasik.flapdiameter" regexp="\d{1,2},\d{2}"/>
+ <lineedit name="ref_behandling.kirurgisk_procedure.lasik.flapdiameter" regexp="\d{1,2},\d{1}"/>
<label caption="mm"/>
<spacer/>
</frame>
@@ -438,7 +322,7 @@
</frame>
<frame layout="hbox">
<label caption="Kantprofil:"/>
- <lineedit name="ref_behandling.kirurgisk_procedure.lasik.kantprofil" regexp="\d{1,3}"/>
+ <lineedit name="ref_behandling.kirurgisk_procedure.lasik.kantprofil" regexp="\d{1,3},\d{1}"/>
<spacer/>
</frame>
</frame>
@@ -459,75 +343,18 @@
<checkbox name="ref_behandling.kirurgisk_procedure.lasek.part1" caption="Efter applikation af 20% alkohol i 20 sek løftes epithelet i de centrale 8 mm til side." truevalue="Efter applikation af 20% alkohol i 20 sek løftes epithelet i de centrale 8 mm til side." falsevalue=""/>
</frame>
- <!-- FLEX frame -->
- <frame name="flex_frame1" caption="FLEX" layout="vbox">
- <label caption="FLEX flappen skæres med:"/>
- <altcombobox name="ref_behandling.kirurgisk_procedure.flex.metode" value="" layout="vbox" script="flex_metode_check">
- <item caption="Ikke udfyldt" value=""/>
- <item caption="Moria M2 90 SU" value="Moria M2 90 SU"/>
- <item caption="Moria M2 130" value="Moria M2 130"/>
- <item caption="Visumax" value="Visumax"/>
- <altitem caption="Andet" value="andet" innerwidget="flex_andet" layout="hbox">
- <label caption="Andet:"/>
- <lineedit name="flex_andet"/>
- </altitem>
- </altcombobox>
- <frame name="flex_moria" layout="vbox">
- <frame layout="hbox">
- <label caption="Variabel sugekop:"/>
- <combobox name="ref_behandling.kirurgisk_procedure.flex.sugekop" value="" layout="vbox">
- <item caption="-1" value="-1"/>
- <item caption="0" value="0"/>
- <item caption="+1" value="+1"/>
- <item caption="+2" value="+2"/>
- </combobox>
- <spacer/>
- </frame>
- <frame layout="hbox">
- <label caption="Variabel hængsel:"/>
- <combobox name="ref_behandling.kirurgisk_procedure.flex.haengsel" value="" layout="vbox">
- <item caption="7,5" value="7,5"/>
- <item caption="8,0" value="8,0"/>
- <item caption="8,5" value="8,5"/>
- </combobox>
- <spacer/>
- </frame>
- </frame>
- <frame name="flex_visumax" layout="vbox">
- <frame layout="hbox">
- <label caption="Flapdiameter:"/>
- <lineedit name="ref_behandling.kirurgisk_procedure.flex.flapdiameter" regexp="\d{1,2},\d{2}"/>
- <label caption="mm"/>
- <spacer/>
- </frame>
- <frame layout="hbox">
- <label caption="Flaptykkelse:"/>
- <lineedit name="ref_behandling.kirurgisk_procedure.flex.flaptykkelse" regexp="\d{1,3}"/>
- <label caption="um"/>
- <spacer/>
- </frame>
- <frame layout="hbox">
- <label caption="Kantprofil:"/>
- <lineedit name="ref_behandling.kirurgisk_procedure.flex.kantprofil" regexp="\d{1,3}"/>
- <spacer/>
- </frame>
- </frame>
- </frame>
-
<!-- End 2nd outer frame -->
</frame>
- <!-- Tilstraebt refraktionsændring frame -->
- <frame name="tilstraebtrefrationsaendring_frame" caption="3. Tilstræbt refraktionsændring" layout="vbox">
+ <!-- Fotoablation frame -->
+ <frame name="fotoablation_frame" caption="3. Fotoablation" layout="vbox">
<frame layout="hbox">
<label caption="Algoritme:"/>
- <combobox name="ref_behandling.kirurgisk_procedure.tilstraebtrefraktionsaendring.algoritme" script="algoritme">
+ <combobox name="ref_behandling.kirurgisk_procedure.fotoablation.algoritme">
<item caption="Smart" value="Smart"/>
<item caption="Tissue saving" value="Tissue saving"/>
<item caption="Topografistyret" value="Topografistyret"/>
- <item caption="Topografi 'smooth'" value="Topografi 'smooth'"/>
<item caption="Bølgefrontstyret" value="Bølgefrontstyret"/>
- <item caption="FLEX" value="FLEX"/>
</combobox>
<spacer/>
</frame>
@@ -538,35 +365,29 @@
</frame>
<frame layout="vbox">
<label caption="Sf:"/>
- <lineedit name="ref_behandling.kirurgisk_procedure.tilstraebtrefraktionsaendring.sf" regexp="[+-]{0,1}\d{1,2},\d{2}" script="lt20gt-25" value=""/>
+ <lineedit name="ref_behandling.kirurgisk_procedure.fotoablation.sf" regexp="[+-]{0,1}\d{1,2},\d{2}" script="lt20gt-25" value=""/>
</frame>
<frame layout="vbox">
<label caption="Cyl:"/>
- <lineedit name="ref_behandling.kirurgisk_procedure.tilstraebtrefraktionsaendring.cyl" regexp="[+-]{0,1}\d{1,2},\d{2}" script="lt10gt-15" value=""/>
+ <lineedit name="ref_behandling.kirurgisk_procedure.fotoablation.cyl" regexp="[+-]{0,1}\d{1,2},\d{2}" script="lt10gt-15" value=""/>
</frame>
<frame layout="vbox">
<label caption="Grader:"/>
- <lineedit name="ref_behandling.kirurgisk_procedure.tilstraebtrefraktionsaendring.grader" regexp="[\d]+" script="lt179gt0" value=""/>
+ <lineedit name="ref_behandling.kirurgisk_procedure.fotoablation.grader" regexp="[\d]+" script="lt179gt0" value=""/>
</frame>
</frame>
<frame layout="hbox">
- <label caption="Behandlingsdiameter:"/>
- <lineedit name="ref_behandling.kirurgisk_procedure.tilstraebtrefraktionsaendring.behandlingsdiameter" script="lt12gt0" regexp="\d{1,2},\d{2}"/>
+ <label caption="Ablationsdiameter:"/>
+ <lineedit name="ref_behandling.kirurgisk_procedure.fotoablation.ablationsdiameter" script="lt12gt0" regexp="\d{1,2},\d{1}"/>
<label caption="mm"/>
<spacer/>
</frame>
<frame layout="hbox">
- <label caption="Behandlingsdybde:"/>
- <lineedit name="ref_behandling.kirurgisk_procedure.tilstraebtrefraktionsaendring.behandlingsdybde" script="lt500gt0" regexp="\d{1,3}"/>
+ <label caption="Ablationsdybde:"/>
+ <lineedit name="ref_behandling.kirurgisk_procedure.fotoablation.ablationsdybde" script="lt500gt0" regexp="\d{1,3}"/>
<label caption="um"/>
<spacer/>
</frame>
- <frame name="flex_algoritme" layout="hbox">
- <label caption="Kanttykkelse:"/>
- <lineedit name="ref_behandling.kirurgisk_procedure.tilstraebtrefraktionsaendring.kanttykkelse" regexp="\d{1,2}"/>
- <label caption="mym"/>
- <spacer/>
- </frame>
</frame>
<!-- Begin 3rd outer frame -->
@@ -592,11 +413,6 @@
<checkbox name="ref_behandling.kirurgisk_procedure.lasek.part2" caption="Epithelet replaceres." truevalue="Epithelet replaceres." falsevalue=""/>
</frame>
- <!-- FLEX frame -->
- <frame name="flex_frame2" caption="FLEX" layout="vbox">
- <checkbox name="ref_behandling.kirurgisk_procedure.flex.part2" caption="FLEX flappen åbnes, vævslinsen ekstraheres, lappen replaceres. Der irrigeres med isotont saltvand, og flappen tørrer i 2 minutter." truevalue="FLEX flappen åbnes, vævslinsen ekstraheres, lappen replaceres. Der irrigeres med isotont saltvand, og flappen tørrer i 2 minutter." falsevalue=""/>
- </frame>
-
<!-- End 3rd outer frame -->
</frame>
diff --git a/server/xml/macros/ref_efterkontrol-overskrift-1.0.xml b/server/xml/macros/ref_efterkontrol-overskrift-1.0.xml
index 8605a0c..e499779 100644
--- a/server/xml/macros/ref_efterkontrol-overskrift-1.0.xml
+++ b/server/xml/macros/ref_efterkontrol-overskrift-1.0.xml
@@ -24,7 +24,6 @@
<combobox name="ref_efterkontrol.overskrift.type">
<item caption="LASIK" value="LASIK"/>
<item caption="PRK" value="PRK"/>
- <item caption="FLEX" value="FLEX"/>
<item caption="reLASIK" value="reLASIK"/>
<item caption="rePRK" value="rePRK"/>
</combobox>
diff --git a/server/xml/macros/ref_foerstedagskontol-overskrift-1.0.xml b/server/xml/macros/ref_foerstedagskontol-overskrift-1.0.xml
index ddcec10..5717a7e 100644
--- a/server/xml/macros/ref_foerstedagskontol-overskrift-1.0.xml
+++ b/server/xml/macros/ref_foerstedagskontol-overskrift-1.0.xml
@@ -18,7 +18,6 @@
<combobox name="ref_foerstedagskontrol.overskrift.type">
<item caption="LASIK" value="LASIK"/>
<item caption="PRK" value="PRK"/>
- <item caption="FLEX" value="FLEX"/>
<item caption="reLASIK" value="reLASIK"/>
<item caption="rePRK" value="rePRK"/>
</combobox>
diff --git a/server/xml/macros/ref_forunders-konklusion-1.0.xml b/server/xml/macros/ref_forunders-konklusion-1.0.xml
index c1db63c..ba59848 100644
--- a/server/xml/macros/ref_forunders-konklusion-1.0.xml
+++ b/server/xml/macros/ref_forunders-konklusion-1.0.xml
@@ -69,7 +69,6 @@
<item caption="Topografistyret LASIK" value="Topografistyret LASIK"/>
<item caption="Topografistyret PRK" value="Topografistyret PRK"/>
<item caption="LASEK" value="LASEK"/>
- <item caption="FLEX" value="FLEX"/>
<altitem caption="Andet" value="andet" layout="hbox" innerwidget="ref_forunders.konklusion.behandling.andet">
<label caption="Andet:"/>
<lineedit name="ref_forunders.konklusion.behandling.andet"/>
diff --git a/server/xml/macros/test_metawidget.xml b/server/xml/macros/test_metawidget.xml
index 0e66ce5..a2d51ea 100644
--- a/server/xml/macros/test_metawidget.xml
+++ b/server/xml/macros/test_metawidget.xml
@@ -10,10 +10,8 @@
<widgets caption="Test Metawidget"
layout="vbox">
- <label caption="&lt;"/>
-
<metawidget layout="vbox" name="dims" format="${test1}: ${test2}" storechildren="true">
- <lineedit name="test1" value="&lt;test"/>
+ <lineedit name="test1" value="test"/>
<checkbox name="test2" value="ja" truevalue="ja" falsevalue="nej" caption="Og svaret er?"/>
</metawidget>
diff --git a/server/xml/macros/visus-autoref-1.0.xml b/server/xml/macros/visus-autoref-1.0.xml
index 4d6a530..439e5b0 100644
--- a/server/xml/macros/visus-autoref-1.0.xml
+++ b/server/xml/macros/visus-autoref-1.0.xml
@@ -284,7 +284,7 @@
<item caption="0,1" value="0,1"/>
<item caption="0,08" value="0,08"/>
<item caption="0,05" value="0,05"/>
- <item caption="&amp;lt;0,05" value="DÃ¥rligere end 0,05"/>
+ <item caption="&amp;lt;0,05" value="&amp;lt;0,05"/>
<item caption="6/60" value="6/60"/>
<item caption="3/60" value="3/60"/>
<item caption="1/18" value="1/18"/>
@@ -470,7 +470,7 @@
<item caption="0,1" value="0,1"/>
<item caption="0,08" value="0,08"/>
<item caption="0,05" value="0,05"/>
- <item caption="&amp;lt;0,05" value="DÃ¥rligere end 0,05"/>
+ <item caption="&amp;lt;0,05" value="&amp;lt;0,05"/>
<item caption="6/60" value="6/60"/>
<item caption="3/60" value="3/60"/>
<item caption="1/18" value="1/18"/>
diff --git a/server/xml/macros/visus-egen_korr-1.0.xml b/server/xml/macros/visus-egen_korr-1.0.xml
index 74f6a40..32c0914 100644
--- a/server/xml/macros/visus-egen_korr-1.0.xml
+++ b/server/xml/macros/visus-egen_korr-1.0.xml
@@ -437,7 +437,7 @@
<item caption="0,1" value="0,1"/>
<item caption="0,08" value="0,08"/>
<item caption="0,05" value="0,05"/>
- <item caption="&amp;lt;0,05" value="DÃ¥rligere end 0,05"/>
+ <item caption="&amp;lt;0,05" value="&amp;lt;0,05"/>
<item caption="6/60" value="6/60"/>
<item caption="3/60" value="3/60"/>
<item caption="1/18" value="1/18"/>
@@ -604,7 +604,7 @@
<item caption="0,1" value="0,1"/>
<item caption="0,08" value="0,08"/>
<item caption="0,05" value="0,05"/>
- <item caption="&amp;lt;0,05" value="DÃ¥rligere end 0,05"/>
+ <item caption="&amp;lt;0,05" value="&amp;lt;0,05"/>
<item caption="6/60" value="6/60"/>
<item caption="3/60" value="3/60"/>
<item caption="1/18" value="1/18"/>
@@ -768,7 +768,7 @@
<item caption="0,1" value="0,1"/>
<item caption="0,08" value="0,08"/>
<item caption="0,05" value="0,05"/>
- <item caption="&amp;lt;0,05" value="DÃ¥rligere end 0,05"/>
+ <item caption="&amp;lt;0,05" value="&amp;lt;0,05"/>
<item caption="6/60" value="6/60"/>
<item caption="3/60" value="3/60"/>
<item caption="1/18" value="1/18"/>
@@ -935,7 +935,7 @@
<item caption="0,1" value="0,1"/>
<item caption="0,08" value="0,08"/>
<item caption="0,05" value="0,05"/>
- <item caption="&amp;lt;0,05" value="DÃ¥rligere end 0,05"/>
+ <item caption="&amp;lt;0,05" value="&amp;lt;0,05"/>
<item caption="6/60" value="6/60"/>
<item caption="3/60" value="3/60"/>
<item caption="1/18" value="1/18"/>
@@ -1102,7 +1102,7 @@
<item caption="0,1" value="0,1"/>
<item caption="0,08" value="0,08"/>
<item caption="0,05" value="0,05"/>
- <item caption="&amp;lt;0,05" value="DÃ¥rligere end 0,05"/>
+ <item caption="&amp;lt;0,05" value="&amp;lt;0,05"/>
<item caption="6/60" value="6/60"/>
<item caption="3/60" value="3/60"/>
<item caption="1/18" value="1/18"/>
diff --git a/server/xml/macros/visus-manifest_refraktion-1.0.xml b/server/xml/macros/visus-manifest_refraktion-1.0.xml
index 68d110f..74b8ea3 100644
--- a/server/xml/macros/visus-manifest_refraktion-1.0.xml
+++ b/server/xml/macros/visus-manifest_refraktion-1.0.xml
@@ -10,6 +10,10 @@
fjern tilsvarende GUI felter der ikke skal bruges
-->
<resume language="lua">
+ function lttoxml(value)
+ return string.gsub(value, '&lt;', '&amp;lt;')
+ end
+
out = ''
if ( getValue('visus.manifest_refraktion.mangler.odxt') == '' or getValue('visus.manifest_refraktion.mangler.osin') == '' or getValue('visus.manifest_refraktion.ou') ~= '' )
then
@@ -21,7 +25,7 @@
out = out .. 'o.dxt: '
if ( getValue('visus.manifest_refraktion.snellen.odxt') ~= '' )
then
- out = out .. getValue('visus.manifest_refraktion.snellen.odxt')
+ out = out .. lttoxml(getValue('visus.manifest_refraktion.snellen.odxt'))
if ( getValue('visus.manifest_refraktion.etdrs.odxt') == '' )
then
out = out .. ', '
@@ -54,7 +58,7 @@
then
if ( getValue('visus.manifest_refraktion.st_hul.snellen.odxt') ~= '' )
then
- out = out .. ', ' .. getValue('visus.manifest_refraktion.st_hul.snellen.odxt')
+ out = out .. ', ' .. lttoxml(getValue('visus.manifest_refraktion.st_hul.snellen.odxt'))
end
if ( getValue('visus.manifest_refraktion.st_hul.etdrs.odxt') ~= '' )
then
@@ -74,7 +78,7 @@
out = out .. 'o.sin: '
if ( getValue('visus.manifest_refraktion.snellen.osin') ~= '' )
then
- out = out .. getValue('visus.manifest_refraktion.snellen.osin')
+ out = out .. lttoxml(getValue('visus.manifest_refraktion.snellen.osin'))
if ( getValue('visus.manifest_refraktion.etdrs.osin') == '' )
then
out = out .. ', '
@@ -107,7 +111,7 @@
then
if ( getValue('visus.manifest_refraktion.st_hul.snellen.osin') ~= '' )
then
- out = out .. ', ' .. getValue('visus.manifest_refraktion.st_hul.snellen.osin')
+ out = out .. ', ' .. lttoxml(getValue('visus.manifest_refraktion.st_hul.snellen.osin'))
end
if ( getValue('visus.manifest_refraktion.st_hul.etdrs.osin') ~= '' )
then
@@ -128,7 +132,7 @@
out = out .. 'o.u: '
if ( getValue('visus.manifest_refraktion.snellen.ou') ~= '' )
then
- out = out .. getValue('visus.manifest_refraktion.snellen.ou')
+ out = out .. lttoxml(getValue('visus.manifest_refraktion.snellen.ou'))
end
if ( getValue('visus.manifest_refraktion.etdrs.ou') ~= '' )
then
@@ -433,7 +437,7 @@
<item caption="0,1" value="0,1"/>
<item caption="0,08" value="0,08"/>
<item caption="0,05" value="0,05"/>
- <item caption="&lt;0,05" value="&lt;0,05"/>
+ <item caption="&amp;lt;0,05" value="&amp;lt;0,05"/>
<item caption="6/60" value="6/60"/>
<item caption="3/60" value="3/60"/>
<item caption="1/18" value="1/18"/>
@@ -600,7 +604,7 @@
<item caption="0,1" value="0,1"/>
<item caption="0,08" value="0,08"/>
<item caption="0,05" value="0,05"/>
- <item caption="&lt;0,05" value="&lt;0,05"/>
+ <item caption="&amp;lt;0,05" value="&amp;lt;0,05"/>
<item caption="6/60" value="6/60"/>
<item caption="3/60" value="3/60"/>
<item caption="1/18" value="1/18"/>
@@ -764,7 +768,7 @@
<item caption="0,1" value="0,1"/>
<item caption="0,08" value="0,08"/>
<item caption="0,05" value="0,05"/>
- <item caption="&lt;0,05" value="&lt;0,05"/>
+ <item caption="&amp;lt;0,05" value="&amp;lt;0,05"/>
<item caption="6/60" value="6/60"/>
<item caption="3/60" value="3/60"/>
<item caption="1/18" value="1/18"/>
@@ -931,7 +935,7 @@
<item caption="0,1" value="0,1"/>
<item caption="0,08" value="0,08"/>
<item caption="0,05" value="0,05"/>
- <item caption="&lt;0,05" value="&lt;0,05"/>
+ <item caption="&amp;lt;0,05" value="&amp;lt;0,05"/>
<item caption="6/60" value="6/60"/>
<item caption="3/60" value="3/60"/>
<item caption="1/18" value="1/18"/>
@@ -1098,7 +1102,7 @@
<item caption="0,1" value="0,1"/>
<item caption="0,08" value="0,08"/>
<item caption="0,05" value="0,05"/>
- <item caption="&lt;0,05" value="&lt;0,05"/>
+ <item caption="&amp;lt;0,05" value="&amp;lt;0,05"/>
<item caption="6/60" value="6/60"/>
<item caption="3/60" value="3/60"/>
<item caption="1/18" value="1/18"/>
diff --git a/server/xml/macros/visus-ou-1.0.xml b/server/xml/macros/visus-ou-1.0.xml
index 9de8d00..3382b4d 100644
--- a/server/xml/macros/visus-ou-1.0.xml
+++ b/server/xml/macros/visus-ou-1.0.xml
@@ -140,7 +140,7 @@
<item caption="0,1" value="0,1"/>
<item caption="0,08" value="0,08"/>
<item caption="0,05" value="0,05"/>
- <item caption="&amp;lt;0,05" value="DÃ¥rligere end 0,05"/>
+ <item caption="&amp;lt;0,05" value="&amp;lt;0,05"/>
<item caption="6/60" value="6/60"/>
<item caption="3/60" value="3/60"/>
<item caption="1/18" value="1/18"/>
diff --git a/server/xml/macros/visus-template-1.0.xml b/server/xml/macros/visus-template-1.0.xml
index 2d56288..7199903 100644
--- a/server/xml/macros/visus-template-1.0.xml
+++ b/server/xml/macros/visus-template-1.0.xml
@@ -11,11 +11,11 @@
-->
<resume language="lua">
function lttoxml(value)
- return string.gsub(value, '&lt;', '&amp;lt;')
+ value = string.gsub(value, '&lt;', '&amp;lt;')
+ return value
end
out = ''
-
if ( getValue('visus.template.mangler.odxt') == '' or getValue('visus.template.mangler.osin') == '' or getValue('visus.template.ou') ~= '' )
then
out = out .. 'Visus template:\n'
@@ -138,7 +138,7 @@
then
out = out .. ', ' .. getValue('visus.template.st_hul.etdrs.osin') .. ' ETDRS'
end
- out = out .. ' st.h.'
+ out = out .. ' st.h.\n'
end
out = out .. '\n'
end
@@ -457,7 +457,7 @@
<item caption="0,1" value="0,1"/>
<item caption="0,08" value="0,08"/>
<item caption="0,05" value="0,05"/>
- <item caption="&amp;lt;0,05" value="DÃ¥rligere end 0,05"/>
+ <item caption="&amp;lt;0,05" value="&amp;lt;0,05"/>
<item caption="6/60" value="6/60"/>
<item caption="3/60" value="3/60"/>
<item caption="1/18" value="1/18"/>
@@ -644,7 +644,7 @@
<item caption="0,1" value="0,1"/>
<item caption="0,08" value="0,08"/>
<item caption="0,05" value="0,05"/>
- <item caption="&amp;lt;0,05" value="DÃ¥rligere end 0,05"/>
+ <item caption="&amp;lt;0,05" value="&amp;lt;0,05"/>
<item caption="6/60" value="6/60"/>
<item caption="3/60" value="3/60"/>
<item caption="1/18" value="1/18"/>
@@ -808,7 +808,7 @@
<item caption="0,1" value="0,1"/>
<item caption="0,08" value="0,08"/>
<item caption="0,05" value="0,05"/>
- <item caption="&amp;lt;0,05" value="DÃ¥rligere end 0,05"/>
+ <item caption="&amp;lt;0,05" value="&amp;lt;0,05"/>
<item caption="6/60" value="6/60"/>
<item caption="3/60" value="3/60"/>
<item caption="1/18" value="1/18"/>
@@ -995,7 +995,7 @@
<item caption="0,1" value="0,1"/>
<item caption="0,08" value="0,08"/>
<item caption="0,05" value="0,05"/>
- <item caption="&amp;lt;0,05" value="DÃ¥rligere end 0,05"/>
+ <item caption="&amp;lt;0,05" value="&amp;lt;0,05"/>
<item caption="6/60" value="6/60"/>
<item caption="3/60" value="3/60"/>
<item caption="1/18" value="1/18"/>
@@ -1162,7 +1162,7 @@
<item caption="0,1" value="0,1"/>
<item caption="0,08" value="0,08"/>
<item caption="0,05" value="0,05"/>
- <item caption="&amp;lt;0,05" value="DÃ¥rligere end 0,05"/>
+ <item caption="&amp;lt;0,05" value="&amp;lt;0,05"/>
<item caption="6/60" value="6/60"/>
<item caption="3/60" value="3/60"/>
<item caption="1/18" value="1/18"/>
diff --git a/server/xml/macros/visus-uden_korr-1.0.xml b/server/xml/macros/visus-uden_korr-1.0.xml
index c5c3405..886b262 100644
--- a/server/xml/macros/visus-uden_korr-1.0.xml
+++ b/server/xml/macros/visus-uden_korr-1.0.xml
@@ -418,7 +418,7 @@
<item caption="0,1" value="0,1"/>
<item caption="0,08" value="0,08"/>
<item caption="0,05" value="0,05"/>
- <item caption="&amp;lt;0,05" value="DÃ¥rligere end 0,05"/>
+ <item caption="&amp;lt;0,05" value="&amp;lt;0,05"/>
<item caption="6/60" value="6/60"/>
<item caption="3/60" value="3/60"/>
<item caption="1/18" value="1/18"/>
@@ -565,7 +565,7 @@
<item caption="0,1" value="0,1"/>
<item caption="0,08" value="0,08"/>
<item caption="0,05" value="0,05"/>
- <item caption="&amp;lt;0,05" value="DÃ¥rligere end 0,05"/>
+ <item caption="&amp;lt;0,05" value="&amp;lt;0,05"/>
<item caption="6/60" value="6/60"/>
<item caption="3/60" value="3/60"/>
<item caption="1/18" value="1/18"/>
@@ -729,7 +729,7 @@
<item caption="0,1" value="0,1"/>
<item caption="0,08" value="0,08"/>
<item caption="0,05" value="0,05"/>
- <item caption="&amp;lt;0,05" value="DÃ¥rligere end 0,05"/>
+ <item caption="&amp;lt;0,05" value="&amp;lt;0,05"/>
<item caption="6/60" value="6/60"/>
<item caption="3/60" value="3/60"/>
<item caption="1/18" value="1/18"/>
@@ -876,7 +876,7 @@
<item caption="0,1" value="0,1"/>
<item caption="0,08" value="0,08"/>
<item caption="0,05" value="0,05"/>
- <item caption="&amp;lt;0,05" value="DÃ¥rligere end 0,05"/>
+ <item caption="&amp;lt;0,05" value="&amp;lt;0,05"/>
<item caption="6/60" value="6/60"/>
<item caption="3/60" value="3/60"/>
<item caption="1/18" value="1/18"/>
@@ -1043,7 +1043,7 @@
<item caption="0,1" value="0,1"/>
<item caption="0,08" value="0,08"/>
<item caption="0,05" value="0,05"/>
- <item caption="&amp;lt;0,05" value="DÃ¥rligere end 0,05"/>
+ <item caption="&amp;lt;0,05" value="&amp;lt;0,05"/>
<item caption="6/60" value="6/60"/>
<item caption="3/60" value="3/60"/>
<item caption="1/18" value="1/18"/>
diff --git a/server/xml/templates/ref_behandling.xml b/server/xml/templates/ref_behandling.xml
index a94f59e..6ad71bb 100644
--- a/server/xml/templates/ref_behandling.xml
+++ b/server/xml/templates/ref_behandling.xml
@@ -4,6 +4,6 @@
<macro name="ref_behandlinghklargoering"/>
<macro name="de_5_trin" requires="ref_behandlinghklargoering"/>
<macro name="ref_behandling.kirurgisk_procedure" requires="ref_behandling.klargoering,de_5_trin"/>
- <macro name="ref_behandling-oejendrypning" requires="ref_behandling.klargoering,de_5_trin,ref_behandling.kirurgisk_procedure"/>
+ <macro name="oejendrypning" requires="ref_behandling.klargoering,de_5_trin,ref_behandling.kirurgisk_procedure"/>
<macro name="supplerende" requires="ref_behandling.klargoering,de_5_trin,ref_behandling.kirurgisk_procedure"/>
</template>
diff --git a/server/xml/templates/ref_foerstedagskontrol.xml b/server/xml/templates/ref_foerstedagskontrol.xml
index a96d79a..cde1ae6 100644
--- a/server/xml/templates/ref_foerstedagskontrol.xml
+++ b/server/xml/templates/ref_foerstedagskontrol.xml
@@ -9,7 +9,7 @@
<macro name="visus-uden_korr" requires="ref_foerstedagskontrol.overskrift"/>
<macro name="ref.spaltelampe" requires="ref_foerstedagskontrol.overskrift"/>
<macro name="ref_komplikationer" requires="ref_foerstedagskontrol.overskrift"/>
- <macro name="ref_behandling-oejendrypning" requires="ref_behandling.klargoering,de_5_trin,ref_behandling.kirurgisk_procedure"/>
+ <macro name="oejendrypning" requires="ref_foerstedagskontrol.overskrift"/>
<macro name="ref_kontrol" requires="ref_foerstedagskontrol.overskrift"/>
</template>
diff --git a/server/xml/templates/ref_forunders.xml b/server/xml/templates/ref_forunders.xml
index c4bd45f..b398df1 100644
--- a/server/xml/templates/ref_forunders.xml
+++ b/server/xml/templates/ref_forunders.xml
@@ -13,7 +13,6 @@
<macro name="ref_aktuelle" requires="henvisning"/>
<header caption="Objektiv undersøgelse"/>
-<!-- <macro name="visus-template" requires="henvisning"/> -->
<macro name="visus-uden_korr" requires="henvisning"/>
<macro name="egen_brille" requires="henvisning"/>
<macro name="visus-egen_korr" requires="henvisning"/>
@@ -36,4 +35,5 @@
<macro name="ref_forunders.konklusion" requires="henvisning"/>
<macro name="information" requires="henvisning"/>
<macro name="ref_forunders.informeret_samtykke" requires="henvisning" compact="true"/>
+
</template>
diff --git a/tools/Makefile.am.test b/tools/Makefile.am.test
new file mode 100644
index 0000000..5c5e8c7
--- /dev/null
+++ b/tools/Makefile.am.test
@@ -0,0 +1,14 @@
+Makefile.am.test: ${TEST_SOURCE_DEPS}
+ ${TEST_SCRIPT_DIR}/testlist > Makefile.am.test
+ @touch Makefile.am
+
+test: Makefile.am.test $(TESTFILES)
+ @echo "All tests done."
+
+test_clean:
+ rm -f $(TESTFILES) $(TESTLOGS)
+
+TESTLOGS = `for F in ${TESTFILES}; do echo $$F.log; done`
+
+CLEANFILES = $(TESTFILES) $(TESTLOGS) Makefile.am.test *~
+
diff --git a/tools/PracroAdd b/tools/PracroAdd
index c2ffdf0..2ceda59 100644
--- a/tools/PracroAdd
+++ b/tools/PracroAdd
@@ -60,11 +60,19 @@ function ccfile() {
local hn=`echo $1 | cut -d'.' -f1 | tr 'a-z.' 'A-Z_'`
echo "#ifdef TEST_${hn}" >> $1;
+ echo "//Additional dependency files" >> $1;
+ echo "//deps:" >> $1;
+ echo "//Required cflags (autoconf vars may be used)" >> $1;
+ echo "//cflags:" >> $1;
+ echo "//Required link options (autoconf vars may be used)" >> $1;
+ echo "//libs:" >> $1;
+ echo "#include \"test.h\"" >> $1;
echo "" >> $1;
- echo "int main()" >> $1;
- echo "{" >> $1;
- echo " return 0;" >> $1;
- echo "}" >> $1;
+ echo "TEST_BEGIN;" >> $1;
+ echo "" >> $1;
+ echo "// TODO: Put some testcode here (see test.h for usable macros)." >> $1;
+ echo "" >> $1;
+ echo "TEST_END;" >> $1;
echo "" >> $1;
echo "#endif/*TEST_${hn}*/" >> $1;
}
diff --git a/tools/test b/tools/test
index 09c2c81..a52609d 100755
--- a/tools/test
+++ b/tools/test
@@ -5,7 +5,9 @@ UPPER=`echo $TEST | tr 'a-z.' 'A-Z_'`
OUTPUT=test_$TEST
DEFINE=TEST_$UPPER
-COMPILE="g++ -g -Wall -Werror -D$DEFINE -o $OUTPUT $*"
+SCRIPTDIR=`dirname $0`
+
+COMPILE="g++ -DHAVE_CONFIG_H -I$SCRIPTDIR -g -Wall -Werror -D$DEFINE -o $OUTPUT $*"
echo -e "\033[0;2mTesting $TEST:"
echo Testing $TEST: > $OUTPUT.log
@@ -26,6 +28,7 @@ if ${COMPILE} >> ${OUTPUT}.log 2>&1; then
else
echo -e "\r\t\t\t\t\t\t[\033[1;31mFailure\033[0;2m]"
echo "[Failure]" >> $OUTPUT.log
+ rm -f $OUTPUT
fi
else
echo -e "\r\t\t\t\t\t\t[\033[1;31mFailure\033[0;2m]"
diff --git a/tools/test.h b/tools/test.h
new file mode 100644
index 0000000..f470162
--- /dev/null
+++ b/tools/test.h
@@ -0,0 +1,262 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set et sw=2 ts=2: */
+/***************************************************************************
+ * test.h
+ *
+ * Wed Dec 16 12:33:19 CET 2009
+ * Copyright 2009 Bent Bisballe Nyeng
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of Pracro.
+ *
+ * Pracro 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 of the License, or
+ * (at your option) any later version.
+ *
+ * Pracro 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 Pracro; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#ifndef __PRACRO_TEST_H__
+#define __PRACRO_TEST_H__
+
+#include <stdio.h>
+
+#define TEST_REPORT { \
+ fprintf(stderr, "\nTest report:\n%d tests\n%d test failed.\n", \
+ TEST_num_tests, TEST_num_fails); \
+ }
+
+#define TEST_BEGIN \
+ int main() { \
+ int TEST_num_fails = 0; \
+ int TEST_num_tests = 0; \
+ {}
+
+#define TEST_END { \
+ TEST_REPORT; \
+ return TEST_num_fails != 0; \
+ } }
+
+#define TEST_OK(m) { \
+ fprintf(stderr, " OK: "m"\n"); \
+ }
+
+#define TEST_FAIL(m) { \
+ fprintf(stderr, " FAIL: "m"\t\t\t<------------\n"); \
+ TEST_num_fails++; \
+ }
+
+#define TEST_FATAL(m) { \
+ fprintf(stderr, "FATAL: %s\t\t\t<============\n", m); \
+ TEST_num_fails++; \
+ { TEST_END; }
+
+#define TEST_MSG(fmt...) { \
+ fprintf(stderr, "\n"); \
+ fprintf(stderr, fmt); \
+ fprintf(stderr, " (line %d)\n", __LINE__); \
+ }
+
+#define TEST_BASE(fmt...) { \
+ TEST_num_tests++; \
+ TEST_MSG(fmt); \
+ }
+
+#define TEST_TRUE(x, fmt...) { \
+ TEST_BASE(fmt); \
+ if(x) { TEST_OK(#x" is true.") } \
+ else { TEST_FAIL(#x" is not true.") } \
+ }
+
+#define TEST_FALSE(x, fmt...) { \
+ TEST_BASE(fmt); \
+ if(!x) { TEST_OK(#x" is false.") } \
+ else { TEST_FAIL(#x" is not false.") } \
+ }
+
+#define TEST_EQUAL(x, y, fmt...) { \
+ TEST_BASE(fmt); \
+ if(x == y) { TEST_OK(#x" and "#y" are equal.") } \
+ else { TEST_FAIL(#x" and "#y" are not equal.") } \
+ }
+
+#define TEST_NOTEQUAL(x, y, fmt...) { \
+ TEST_BASE(fmt); \
+ if(x != y) { TEST_OK(#x" and "#y" are not equal.") } \
+ else { TEST_FAIL(#x" and "#y" are equal.") } \
+ }
+
+#define TEST_GREATER_THAN(x, y, fmt...) { \
+ TEST_BASE(fmt); \
+ if(x > y) { TEST_OK(#x" are greater than "#y".") } \
+ else { TEST_FAIL(#x" are not greater than "#y".") } \
+ }
+
+#define TEST_LESS_THAN(x, y, fmt...) { \
+ TEST_BASE(fmt); \
+ if(x < y) { TEST_OK(#x" are less than "#y".") } \
+ else { TEST_FAIL(#x" are not less than "#y".") } \
+ }
+
+#define TEST_EQUAL_STR(x, y, fmt...) { \
+ TEST_BASE(fmt); \
+ std::string s1 = x; \
+ std::string s2 = y; \
+ fprintf(stderr, "Comparing: \"%s\" == \"%s\"\n", \
+ s1.c_str(), s2.c_str()); \
+ if(s1 == s2) { \
+ TEST_OK(#x" and "#y" are equal."); \
+ } else { \
+ TEST_FAIL(#x" and "#y" are not equal."); \
+ } \
+ }
+
+#define TEST_NOTEQUAL_STR(x, y, fmt...) { \
+ TEST_BASE(fmt); \
+ std::string s1 = x; \
+ std::string s2 = y; \
+ fprintf(stderr, "Comparing: \"%s\" != \"%s\"\n", \
+ s1.c_str(), s2.c_str()); \
+ if(s1 != s2) { \
+ TEST_OK(#x" and "#y" not are equal."); \
+ } else { \
+ TEST_FAIL(#x" and "#y" are equal."); \
+ } \
+ }
+
+#define TEST_EQUAL_INT(x, y, fmt...) { \
+ TEST_BASE(fmt); \
+ int i1 = x; \
+ int i2 = y; \
+ fprintf(stderr, "Comparing: \"%d\" == \"%d\"\n", i1, i2); \
+ if(i1 == i2) { \
+ TEST_OK(#x" and "#y" are equal."); \
+ } else { \
+ TEST_FAIL(#x" and "#y" are not equal."); \
+ } \
+ }
+
+#define TEST_NOTEQUAL_INT(x, y, fmt...) { \
+ TEST_BASE(fmt); \
+ int i1 = x; \
+ int i2 = y; \
+ fprintf(stderr, "Comparing: \"%d\" != \"%d\"\n", i1, i2); \
+ if(i1 != i2) { \
+ TEST_OK(#x" and "#y" are not equal."); \
+ } else { \
+ TEST_FAIL(#x" and "#y" are equal."); \
+ } \
+ }
+
+#define TEST_EQUAL_FLOAT(x, y, fmt...) { \
+ TEST_BASE(fmt); \
+ double d1 = x; \
+ double d2 = y; \
+ fprintf(stderr, "Comparing: \"%f\" == \"%f\"\n", d1, d2); \
+ if(d1 == d2) { \
+ TEST_OK(#x" and "#y" are equal."); \
+ } else { \
+ TEST_FAIL(#x" and "#y" are not equal."); \
+ } \
+ }
+
+#define TEST_NOTEQUAL_FLOAT(x, y, fmt...) { \
+ TEST_BASE(fmt); \
+ double d1 = x; \
+ double d2 = y; \
+ fprintf(stderr, "Comparing: \"%f\" != \"%f\"\n", d1, d2); \
+ if(d1 != d2) { \
+ TEST_OK(#x" and "#y" are not equal."); \
+ } else { \
+ TEST_FAIL(#x" and "#y" are equal."); \
+ } \
+ }
+
+#define TEST_GREATER_THAN_INT(x, y, fmt...) { \
+ TEST_BASE(fmt); \
+ int i1 = x; \
+ int i2 = y; \
+ fprintf(stderr, "Comparing: \"%d\" > \"%d\"\n", i1, i2); \
+ if(i1 > i2) { \
+ TEST_OK(#x" are greater than "#y"."); \
+ } else { \
+ TEST_FAIL(#x" are not greater than "#y"."); \
+ } \
+ }
+
+#define TEST_LESS_THAN_INT(x, y, fmt...) { \
+ TEST_BASE(fmt); \
+ int i1 = x; \
+ int i2 = y; \
+ fprintf(stderr, "Comparing: \"%d\" < \"%d\"\n", i1, i2); \
+ if(i1 < i2) { \
+ TEST_OK(#x" are less than "#y"."); \
+ } else { \
+ TEST_FAIL(#x" are not less than "#y"."); \
+ } \
+ }
+
+#define TEST_GREATER_THAN_FLOAT(x, y, fmt...) { \
+ TEST_BASE(fmt); \
+ double d1 = x; \
+ double d2 = y; \
+ fprintf(stderr, "Comparing: \"%f\" > \"%f\"\n", d1, d2); \
+ if(d1 > d2) { \
+ TEST_OK(#x" are greater than "#y"."); \
+ } else { \
+ TEST_FAIL(#x" are not greater than "#y"."); \
+ } \
+ }
+
+#define TEST_LESS_THAN_FLOAT(x, y, fmt...) { \
+ TEST_BASE(fmt); \
+ double d1 = x; \
+ double d2 = y; \
+ fprintf(stderr, "Comparing: \"%f\" < \"%f\"\n", d1, d2); \
+ if(d1 < d2) { \
+ TEST_OK(#x" are less than "#y"."); \
+ } else { \
+ TEST_FAIL(#x" are not less than "#y"."); \
+ } \
+ }
+
+#define TEST_EXCEPTION(x, y, fmt...) { \
+ TEST_BASE(fmt); \
+ try { \
+ x; \
+ TEST_FAIL("Exception "#y" was not trown."); \
+ } catch( y &e ) { \
+ TEST_OK("Exception "#y" was thrown as expected."); \
+ } \
+ }
+
+#define TEST_NOTEXCEPTION(x, y, fmt...) { \
+ TEST_BASE(fmt); \
+ try { \
+ x; \
+ TEST_OK("Exception "#y" was not trown as expected"); \
+ } catch( y &e ) { \
+ TEST_FAIL("Exception "#y" was thrown."); \
+ } \
+ }
+
+#define TEST_NOEXCEPTION(x, fmt...) { \
+ TEST_BASE(fmt); \
+ try { \
+ x; \
+ TEST_OK("Exception was not trown as expected"); \
+ } catch( ... ) { \
+ TEST_FAIL("Exception was thrown."); \
+ } \
+ }
+
+#endif/*__PRACRO_TEST_H__*/
diff --git a/tools/testlist b/tools/testlist
new file mode 100755
index 0000000..c42824f
--- /dev/null
+++ b/tools/testlist
@@ -0,0 +1,31 @@
+#!/bin/bash
+
+SCRIPTDIR=`dirname $0`
+
+grep -l "TEST_BEGIN" *.cc > tmp
+
+echo -n "TESTFILES="
+while read LINE
+do
+ FILE=$LINE
+ NAME=`echo $FILE | cut -d'.' -f1`
+ TEST=test_$NAME
+ echo -ne "$TEST "
+done < tmp
+echo ""
+echo ""
+
+while read LINE
+do
+ FILE=$LINE
+ NAME=`echo $FILE | cut -d'.' -f1`
+ DEPS=`cat $FILE | grep "deps:" | cut -d':' -f2`
+ LIBS=`cat $FILE | grep "libs:" | cut -d':' -f2`
+ CFLAGS=`cat $FILE | grep "cflags:" | cut -d':' -f2`
+ TEST=test_$NAME
+ echo "$TEST: $FILE $DEPS"
+ echo -e "\t@${SCRIPTDIR}/test $FILE $DEPS $CFLAGS $LIBS"
+ echo ""
+done < tmp
+
+rm -f tmp \ No newline at end of file