summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorSebastian Reichel <sre@ring0.de>2013-03-26 15:52:57 +0100
committerSebastian Reichel <sre@ring0.de>2013-03-26 15:52:57 +0100
commit7bfb48ef84384ff0460f273ea5841fba628d2a46 (patch)
tree898d019f33a554f03cac91495adcb7165344382e /src
parent03a4e9f901cd36792de2172b4ebb8f6e852fe1cd (diff)
downloadserial-barcode-scanner-7bfb48ef84384ff0460f273ea5841fba628d2a46.tar.bz2
code restructure
Diffstat (limited to 'src')
-rw-r--r--src/Makefile9
-rw-r--r--src/audio/Makefile9
-rw-r--r--src/audio/audio-interface.vala23
-rw-r--r--src/audio/audio.vala (renamed from src/audio.vala)12
-rw-r--r--src/audio/main.vala38
-rw-r--r--src/config/Makefile9
-rw-r--r--src/config/config-interface.vala26
-rw-r--r--src/config/config.vala62
-rw-r--r--src/config/main.vala40
-rw-r--r--src/curses-ui/Makefile9
-rw-r--r--src/curses-ui/clock.vala (renamed from src/ui/clock.vala)15
-rw-r--r--src/curses-ui/curses-ui.vala (renamed from src/ui/curses-ui.vala)15
-rw-r--r--src/curses-ui/dialog.vala (renamed from src/ui/dialog.vala)15
-rw-r--r--src/curses-ui/logo.vala45
-rw-r--r--src/curses-ui/main.vala49
-rw-r--r--src/curses-ui/message_box.vala (renamed from src/ui/message_box.vala)15
-rw-r--r--src/curses-ui/numbers.vala (renamed from src/ui/numbers.vala)15
-rw-r--r--src/curses-ui/status.vala39
-rw-r--r--src/database/Makefile9
-rw-r--r--src/database/database.vala (renamed from src/db.vala)359
-rw-r--r--src/database/db-interface.vala148
-rw-r--r--src/database/main.vala44
-rw-r--r--src/main.vala131
-rw-r--r--src/pdf-invoice/Makefile9
-rw-r--r--src/pdf-invoice/main.vala36
-rw-r--r--src/pdf-invoice/pdf-invoice-interface.vala54
-rw-r--r--src/pdf-invoice/pdf-invoice.vala98
-rw-r--r--src/pdf-invoice/test.vala47
-rw-r--r--src/pgp/Makefile9
-rw-r--r--src/pgp/main.vala53
-rw-r--r--src/pgp/pgp-interface.vala21
-rw-r--r--src/pgp/pgp.vala (renamed from src/admin.vala)82
-rw-r--r--src/scanner-session/Makefile9
-rw-r--r--src/scanner-session/main.vala38
-rw-r--r--src/scanner-session/scannersession-interface.vala25
-rw-r--r--src/scanner-session/scannersession.vala (renamed from src/scannersession.vala)93
-rw-r--r--src/serial-device/Makefile9
-rw-r--r--src/serial-device/main.vala47
-rw-r--r--src/serial-device/serial-device-interface.vala20
-rw-r--r--src/serial-device/serial-device.vala (renamed from src/device.vala)7
-rw-r--r--src/ui/logo.vala30
-rw-r--r--src/ui/status.vala24
-rw-r--r--src/web/Makefile9
-rw-r--r--src/web/csv.vala75
-rw-r--r--src/web/main.vala35
-rw-r--r--src/web/template.vala (renamed from src/template.vala)0
-rw-r--r--src/web/web.vala (renamed from src/web.vala)16
-rw-r--r--src/web/websession.vala (renamed from src/websession.vala)0
48 files changed, 1372 insertions, 610 deletions
diff --git a/src/Makefile b/src/Makefile
new file mode 100644
index 0000000..da0bf41
--- /dev/null
+++ b/src/Makefile
@@ -0,0 +1,9 @@
+DAEMONS=audio config curses-ui database pdf-invoice pgp scanner-session serial-device web
+
+all:
+ @$(foreach dir,$(DAEMONS),cd $(dir) && make all && cd ..;)
+
+clean:
+ @$(foreach dir,$(DAEMONS),cd $(dir) && make clean && cd ..;)
+
+.PHONY: all clean
diff --git a/src/audio/Makefile b/src/audio/Makefile
new file mode 100644
index 0000000..a6fd629
--- /dev/null
+++ b/src/audio/Makefile
@@ -0,0 +1,9 @@
+all: audio
+
+audio: main.vala audio.vala audio-interface.vala
+ valac -o $@ --pkg gstreamer-0.10 --pkg gio-2.0 $^
+
+clean:
+ rm -rf audio
+
+.PHONY: all clean
diff --git a/src/audio/audio-interface.vala b/src/audio/audio-interface.vala
new file mode 100644
index 0000000..89d4a6f
--- /dev/null
+++ b/src/audio/audio-interface.vala
@@ -0,0 +1,23 @@
+/* Copyright 2013, Sebastian Reichel <sre@ring0.de>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+[DBus (name = "io.mainframe.shopsystem.AudioPlayer")]
+public interface AudioPlayer : Object {
+ public abstract signal void end_of_stream();
+
+ public abstract void play_system(string file) throws IOError;
+ public abstract string get_random_user_theme() throws IOError;
+ public abstract void play_user(string theme, string type) throws IOError;
+}
diff --git a/src/audio.vala b/src/audio/audio.vala
index 3f22e6d..0225c01 100644
--- a/src/audio.vala
+++ b/src/audio/audio.vala
@@ -1,4 +1,4 @@
-/* Copyright 2012, Sebastian Reichel <sre@ring0.de>
+/* Copyright 2012-2013, Sebastian Reichel <sre@ring0.de>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -13,14 +13,15 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-public class AudioPlayer {
+[DBus (name = "io.mainframe.shopsystem.AudioPlayer")]
+public class AudioPlayerImplementation {
private dynamic Gst.Element p;
string path;
public signal void end_of_stream();
private bool bus_callback(Gst.Bus bus, Gst.Message message) {
- switch (message.type) {
+ switch(message.type) {
case Gst.MessageType.EOS:
end_of_stream();
break;
@@ -29,7 +30,7 @@ public class AudioPlayer {
return true;
}
- public AudioPlayer() {
+ public AudioPlayerImplementation() {
path = Environment.get_current_dir()+"/sounds/";
var alsa = Gst.ElementFactory.make("alsasink", "alsa");
@@ -57,7 +58,8 @@ public class AudioPlayer {
return result;
} catch (Error e) {
- write_to_log("Error: %s\n", e.message);
+ // TODO
+ //write_to_log("Error: %s\n", e.message);
return {};
}
}
diff --git a/src/audio/main.vala b/src/audio/main.vala
new file mode 100644
index 0000000..f3f64f4
--- /dev/null
+++ b/src/audio/main.vala
@@ -0,0 +1,38 @@
+/* Copyright 2013, Sebastian Reichel <sre@ring0.de>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+AudioPlayerImplementation player;
+
+public static int main(string[] args) {
+ Bus.own_name(
+ BusType.SESSION,
+ "io.mainframe.shopsystem.AudioPlayer",
+ BusNameOwnerFlags.NONE,
+ on_bus_aquired,
+ () => {},
+ () => stderr.printf("Could not aquire name\n"));
+
+ new MainLoop().run();
+
+ return 0;
+}
+
+void on_bus_aquired(DBusConnection con) {
+ try {
+ con.register_object("/io/mainframe/shopsystem/audio", player);
+ } catch(IOError e) {
+ stderr.printf("Could not register service\n");
+ }
+}
diff --git a/src/config/Makefile b/src/config/Makefile
new file mode 100644
index 0000000..0e81ee9
--- /dev/null
+++ b/src/config/Makefile
@@ -0,0 +1,9 @@
+all: config
+
+config: main.vala config.vala config-interface.vala
+ valac -o $@ --pkg gio-2.0 $^
+
+clean:
+ rm -rf config
+
+.PHONY: all clean
diff --git a/src/config/config-interface.vala b/src/config/config-interface.vala
new file mode 100644
index 0000000..c34e3a7
--- /dev/null
+++ b/src/config/config-interface.vala
@@ -0,0 +1,26 @@
+/* Copyright 2013, Sebastian Reichel <sre@ring0.de>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+[DBus (name = "io.mainframe.shopsystem.Config")]
+public interface Config : Object {
+ public abstract bool has_group(string group_name) throws IOError, KeyFileError;
+ public abstract bool has_key(string group_name, string key) throws IOError, KeyFileError;
+ public abstract string get_string(string group_name, string key) throws IOError, KeyFileError;
+ public abstract bool get_boolean(string group_name, string key) throws IOError, KeyFileError;
+ public abstract int get_integer(string group_name, string key) throws IOError, KeyFileError;
+ public abstract int64 get_int64(string group_name, string key) throws IOError, KeyFileError;
+ public abstract uint64 get_uint64(string group_name, string key) throws IOError, KeyFileError;
+ public abstract double get_double(string group_name, string key) throws IOError, KeyFileError;
+}
diff --git a/src/config/config.vala b/src/config/config.vala
new file mode 100644
index 0000000..60fd835
--- /dev/null
+++ b/src/config/config.vala
@@ -0,0 +1,62 @@
+/* Copyright 2013, Sebastian Reichel <sre@ring0.de>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+[DBus (name = "io.mainframe.shopsystem.Config")]
+public class Cfg {
+
+ private KeyFile file;
+
+ public Cfg(string file) {
+ try {
+ this.file = new KeyFile();
+ this.file.load_from_file(file, KeyFileFlags.NONE);
+ } catch(Error e) {
+ error("Could not load configuration file: %s", e.message);
+ }
+ }
+
+ public bool has_group(string group_name) throws KeyFileError {
+ return file.has_group(group_name);
+ }
+
+ public bool has_key(string group_name, string key) throws KeyFileError {
+ return file.has_key(group_name, key);
+ }
+
+ public string get_string(string group_name, string key) throws KeyFileError {
+ return file.get_string(group_name, key);
+ }
+
+ public bool get_boolean(string group_name, string key) throws KeyFileError {
+ return file.get_boolean(group_name, key);
+ }
+
+ public int get_integer(string group_name, string key) throws KeyFileError {
+ return file.get_integer(group_name, key);
+ }
+
+ public int64 get_int64(string group_name, string key) throws KeyFileError {
+ return file.get_int64(group_name, key);
+ }
+
+ public uint64 get_uint64(string group_name, string key) throws KeyFileError {
+ return file.get_uint64(group_name, key);
+ }
+
+ public double get_double(string group_name, string key) throws KeyFileError {
+ return file.get_double(group_name, key);
+ }
+
+}
diff --git a/src/config/main.vala b/src/config/main.vala
new file mode 100644
index 0000000..aa971d6
--- /dev/null
+++ b/src/config/main.vala
@@ -0,0 +1,40 @@
+/* Copyright 2013, Sebastian Reichel <sre@ring0.de>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+Cfg cfg;
+
+public static int main(string[] args) {
+ cfg = new Cfg("../../ktt-shopsystem.cfg");
+
+ Bus.own_name(
+ BusType.SESSION,
+ "io.mainframe.shopsystem.Config",
+ BusNameOwnerFlags.NONE,
+ on_bus_aquired,
+ () => {},
+ () => stderr.printf("Could not aquire name\n"));
+
+ new MainLoop().run();
+
+ return 0;
+}
+
+void on_bus_aquired(DBusConnection con) {
+ try {
+ con.register_object("/io/mainframe/shopsystem/config", cfg);
+ } catch(IOError e) {
+ stderr.printf("Could not register service\n");
+ }
+}
diff --git a/src/curses-ui/Makefile b/src/curses-ui/Makefile
new file mode 100644
index 0000000..5d168ba
--- /dev/null
+++ b/src/curses-ui/Makefile
@@ -0,0 +1,9 @@
+all: curses-ui
+
+curses-ui: clock.vala curses-ui.vala dialog.vala logo.vala main.vala message_box.vala numbers.vala status.vala ../audio/audio-interface.vala
+ valac -o $@ --pkg curses -X -lncursesw --pkg posix --pkg gio-2.0 $^
+
+clean:
+ rm -rf curses-ui
+
+.PHONY: all clean
diff --git a/src/ui/clock.vala b/src/curses-ui/clock.vala
index e38ad9c..dd3ddcd 100644
--- a/src/ui/clock.vala
+++ b/src/curses-ui/clock.vala
@@ -1,3 +1,18 @@
+/* Copyright 2013, Sebastian Reichel <sre@ring0.de>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
using Curses;
public class ClockWindow {
diff --git a/src/ui/curses-ui.vala b/src/curses-ui/curses-ui.vala
index 6676eea..ec007f2 100644
--- a/src/ui/curses-ui.vala
+++ b/src/curses-ui/curses-ui.vala
@@ -1,3 +1,18 @@
+/* Copyright 2013, Sebastian Reichel <sre@ring0.de>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
public class CursesUI {
MessageBox messages;
Dialog dialog;
diff --git a/src/ui/dialog.vala b/src/curses-ui/dialog.vala
index 29782e5..a8585d4 100644
--- a/src/ui/dialog.vala
+++ b/src/curses-ui/dialog.vala
@@ -1,3 +1,18 @@
+/* Copyright 2013, Sebastian Reichel <sre@ring0.de>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
using Curses;
public class Dialog {
diff --git a/src/curses-ui/logo.vala b/src/curses-ui/logo.vala
new file mode 100644
index 0000000..dbc716d
--- /dev/null
+++ b/src/curses-ui/logo.vala
@@ -0,0 +1,45 @@
+/* Copyright 2013, Sebastian Reichel <sre@ring0.de>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+using Curses;
+
+public class Logo {
+ Window win;
+
+ public Logo() {
+ win = new Window(8, COLS - 2, 0, 1);
+ win.bkgdset(COLOR_PAIR(1) | Attribute.BOLD);
+
+ win.addstr("\n");
+ win.addstr(" _ ___ _____ ____ _ \n");
+ win.addstr(" | |/ / ||_ _| / ___|| |__ ___ _ __ \n");
+ win.addstr(" | ' /| __|| | \\___ \\| '_ \\ / _ \\| '_ \\ \n");
+ win.addstr(" | . \\| |_ | | ___) | | | | (_) | |_) )\n");
+ win.addstr(" |_|\\_\\\\__||_| |____/|_| |_|\\___/| .__/ \n");
+ win.addstr(" |_| \n");
+
+ win.clrtobot();
+
+ win.box(0, 0);
+
+ win.refresh();
+ }
+
+ public void redraw() {
+ win.touchwin();
+ win.refresh();
+ }
+
+}
diff --git a/src/curses-ui/main.vala b/src/curses-ui/main.vala
new file mode 100644
index 0000000..1d79c43
--- /dev/null
+++ b/src/curses-ui/main.vala
@@ -0,0 +1,49 @@
+/* Copyright 2013, Sebastian Reichel <sre@ring0.de>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+public MainLoop loop;
+
+public static int main(string[] args) {
+ /* handle unix signals */
+ Unix.signal_add(Posix.SIGTERM, handle_signals);
+ Unix.signal_add(Posix.SIGINT, handle_signals);
+
+ AudioPlayer audio = Bus.get_proxy_sync(BusType.SESSION, "io.mainframe.shopsystem.AudioPlayer", "/io/mainframe/shopsystem/audio");
+
+ var ui = new CursesUI();
+
+ ui.log("KtT Shop System has been started");
+ audio.play_system("startup.ogg");
+
+ /* run mainloop */
+ loop.run();
+
+ ui.log("Stopping Shop System");
+ audio.play_system("shutdown.ogg");
+
+ /* we need to run the mainloop to play audio */
+ audio.end_of_stream.connect(() => { loop.quit(); });
+ loop.run();
+
+ /* leave curses mode */
+ ui.exit();
+
+ return 0;
+}
+
+bool handle_signals() {
+ loop.quit();
+ return false;
+}
diff --git a/src/ui/message_box.vala b/src/curses-ui/message_box.vala
index 4f9c3f6..cc258b4 100644
--- a/src/ui/message_box.vala
+++ b/src/curses-ui/message_box.vala
@@ -1,3 +1,18 @@
+/* Copyright 2013, Sebastian Reichel <sre@ring0.de>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
using Curses;
public class MessageBox {
diff --git a/src/ui/numbers.vala b/src/curses-ui/numbers.vala
index 8ee00d5..200cf63 100644
--- a/src/ui/numbers.vala
+++ b/src/curses-ui/numbers.vala
@@ -1,3 +1,18 @@
+/* Copyright 2013, Sebastian Reichel <sre@ring0.de>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
public class AsciiNumbers {
public string[] zero = {
diff --git a/src/curses-ui/status.vala b/src/curses-ui/status.vala
new file mode 100644
index 0000000..5be6a00
--- /dev/null
+++ b/src/curses-ui/status.vala
@@ -0,0 +1,39 @@
+/* Copyright 2013, Sebastian Reichel <sre@ring0.de>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+using Curses;
+
+public class StatusPanel {
+ Window win;
+
+ public StatusPanel() {
+ win = new Window(1, COLS - 2, LINES-1, 1);
+ win.bkgdset(COLOR_PAIR(2) | Attribute.BOLD);
+
+ win.clrtobot();
+ win.refresh();
+ }
+
+ public void set(string msg) {
+ win.mvaddstr(0,1, msg);
+ win.clrtobot();
+ win.refresh();
+ }
+
+ public void redraw() {
+ win.touchwin();
+ win.refresh();
+ }
+}
diff --git a/src/database/Makefile b/src/database/Makefile
new file mode 100644
index 0000000..70253d2
--- /dev/null
+++ b/src/database/Makefile
@@ -0,0 +1,9 @@
+all: db
+
+db: main.vala database.vala db-interface.vala ../price.vapi
+ valac -o $@ --pkg sqlite3 --pkg gee-1.0 --pkg gio-2.0 $^
+
+clean:
+ rm -rf db
+
+.PHONY: all clean
diff --git a/src/db.vala b/src/database/database.vala
index dc1c834..640e175 100644
--- a/src/db.vala
+++ b/src/database/database.vala
@@ -1,4 +1,4 @@
-/* Copyright 2012, Sebastian Reichel <sre@ring0.de>
+/* Copyright 2012-2013, Sebastian Reichel <sre@ring0.de>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -15,109 +15,8 @@
public const int day_in_seconds = 24*60*60;
-public struct StockEntry {
- public string id;
- public string name;
- public int amount;
- public string memberprice;
- public string guestprice;
-}
-
-public struct PriceEntry {
- public int64 valid_from;
- public Price memberprice;
- public Price guestprice;
-}
-
-public struct RestockEntry {
- public int64 timestamp;
- public int amount;
- public string price;
- public int supplier;
- public int64 best_before_date;
-}
-
-public struct Supplier {
- public int64 id;
- public string name;
- public string postal_code;
- public string city;
- public string street;
- public string phone;
- public string website;
-}
-
-public struct UserInfo {
- public int id;
- public string firstname;
- public string lastname;
- public string email;
- public string gender;
- public string street;
- public int postcode;
- public string city;
- public string pgp;
-
- public bool equals(UserInfo x) {
- if(id != x.id) return false;
- if(firstname != x.firstname) return false;
- if(lastname != x.lastname) return false;
- if(email != x.email) return false;
- if(gender != x.gender) return false;
- if(street != x.street) return false;
- if(postcode != x.postcode) return false;
- if(city != x.city) return false;
- if(pgp != x.pgp) return false;
-
- return true;
- }
-
- public bool exists_in_db() {
- if(id in db.get_member_ids())
- return true;
- else
- return false;
- }
-
- public bool equals_db() {
- return this.equals(db.get_user_info(id));
- }
-}
-
-public struct UserAuth {
- public int id;
- public bool disabled;
- public bool superuser;
-}
-
-public struct Product {
- public uint64 ean;
- public string name;
-}
-
-public struct InvoiceEntry {
- public int64 timestamp;
- Product product;
- Price price;
-}
-
-public struct StatsInfo {
- public int count_articles;
- public int count_users;
- public Price stock_value;
- public Price sales_total;
- public Price profit_total;
- public Price sales_today;
- public Price profit_today;
- public Price sales_this_month;
- public Price profit_this_month;
- public Price sales_per_day;
- public Price profit_per_day;
- public Price sales_per_month;
- public Price profit_per_month;
-}
-
-public class Database {
+[DBus (name = "io.mainframe.shopsystem.Database")]
+public class DataBase : Object {
private class Statement {
private Sqlite.Statement stmt;
@@ -158,7 +57,8 @@ public class Database {
}
public string column_text(int index) {
- return stmt.column_text(index);
+ var result = stmt.column_text(index);
+ return (result != null) ? result : "";
}
public int64 column_int64(int index) {
@@ -169,8 +69,10 @@ public class Database {
private Sqlite.Database db;
private static Gee.HashMap<string,string> queries = new Gee.HashMap<string,string>();
private static Gee.HashMap<string,Statement> statements = new Gee.HashMap<string,Statement>();
+ //private static HashTable<string,string> queries = new HashTable<string,string>(null, null);
+ //private static HashTable<string,Statement> statements = new HashTable<string,Statement>(null, null);
- public Database(string file) {
+ public DataBase(string file) {
int rc;
rc = Sqlite.Database.open(file, out db);
@@ -224,10 +126,15 @@ public class Database {
foreach(var entry in queries.entries) {
statements[entry.key] = new Statement(db, entry.value);
}
+#if 0
+ foreach(var key in queries.get_keys()) {
+ statements[key] = new Statement(db, queries[key]);
+ }
+#endif
}
- public Gee.HashMap<string,string> get_products() {
- var result = new Gee.HashMap<string,string>(null, null);
+ public GLib.HashTable<string,string> get_products() {
+ var result = new GLib.HashTable<string,string>(null, null);
statements["products"].reset();
while(statements["products"].step() == Sqlite.ROW)
@@ -236,6 +143,7 @@ public class Database {
return result;
}
+#if 0
public stock get_stats_stock() {
var result = new stock();
var now = time_t();
@@ -265,7 +173,9 @@ public class Database {
return result;
}
+#endif
+#if 0
public profit_per_product get_stats_profit_per_products() {
var result = new profit_per_product();
@@ -281,7 +191,9 @@ public class Database {
return result;
}
+#endif
+#if 0
public profit_per_weekday get_stats_profit_per_weekday() {
var result = new profit_per_weekday();
@@ -313,7 +225,9 @@ public class Database {
return result;
}
+#endif
+#if 0
public profit_per_day get_stats_profit_per_day() {
var result = new profit_per_day();
var to = time_t();
@@ -340,11 +254,12 @@ public class Database {
return result;
}
+#endif
- public Gee.List<StockEntry?> get_stock() {
- var result = new Gee.ArrayList<StockEntry?>();
- statements["stock_status"].reset();
+ public StockEntry[] get_stock() {
+ StockEntry[] result = {};
+ statements["stock_status"].reset();
while(statements["stock_status"].step() == Sqlite.ROW) {
StockEntry entry = {
statements["stock_status"].column_text(0),
@@ -360,17 +275,17 @@ public class Database {
entry.memberprice = @"$mprice";
entry.guestprice = @"$gprice";
- result.add(entry);
+ result += entry;
}
return result;
}
- public Gee.List<PriceEntry?> get_prices(uint64 product) {
- var result = new Gee.ArrayList<PriceEntry?>();
+ public PriceEntry[] get_prices(uint64 product) {
+ PriceEntry[] result = {};
+
statements["prices"].reset();
statements["prices"].bind_text(1, "%llu".printf(product));
-
while(statements["prices"].step() == Sqlite.ROW) {
PriceEntry entry = {
statements["prices"].column_int64(0),
@@ -378,17 +293,17 @@ public class Database {
statements["prices"].column_int(2)
};
- result.add(entry);
+ result += entry;
}
return result;
}
- public Gee.List<RestockEntry?> get_restocks(uint64 product) {
- var result = new Gee.ArrayList<RestockEntry?>();
+ public RestockEntry[] get_restocks(uint64 product) {
+ RestockEntry[] result = {};
+
statements["restocks"].reset();
statements["restocks"].bind_text(1, "%llu".printf(product));
-
while(statements["restocks"].step() == Sqlite.ROW) {
RestockEntry entry = {
statements["restocks"].column_int64(0),
@@ -400,13 +315,13 @@ public class Database {
entry.supplier = statements["restocks"].column_int(3);
entry.best_before_date = statements["restocks"].column_int64(4);
- result.add(entry);
+ result += entry;
}
return result;
}
- public bool buy(int32 user, uint64 article) {
+ public bool buy(int32 user, uint64 article) throws DatabaseError {
int rc = 0;
int64 timestamp = (new DateTime.now_utc()).to_unix();
@@ -417,12 +332,12 @@ public class Database {
rc = statements["purchase"].step();
if(rc != Sqlite.DONE)
- error("[internal error: %d]".printf(rc));
+ throw new DatabaseError.INTERNAL_ERROR("internal error: %d", rc);
return true;
}
- public string get_product_name(uint64 article) {
+ public string get_product_name(uint64 article) throws DatabaseError {
statements["product_name"].reset();
statements["product_name"].bind_text(1, "%llu".printf(article));
@@ -432,13 +347,13 @@ public class Database {
case Sqlite.ROW:
return statements["product_name"].column_text(0);
case Sqlite.DONE:
- return "unbekanntes Produkt: %llu".printf(article);
+ throw new DatabaseError.PRODUCT_NOT_FOUND("unknown product: %llu", article);
default:
- return "[internal error: %d]".printf(rc);
+ throw new DatabaseError.INTERNAL_ERROR("internal error: %d", rc);
}
}
- public int get_product_amount(uint64 article) {
+ public int get_product_amount(uint64 article) throws DatabaseError {
statements["product_amount"].reset();
statements["product_amount"].bind_text(1, "%llu".printf(article));
@@ -448,15 +363,13 @@ public class Database {
case Sqlite.ROW:
return statements["product_amount"].column_int(0);
case Sqlite.DONE:
- warning("unbekanntes Produkt: %llu".printf(article));
- return -1;
+ throw new DatabaseError.PRODUCT_NOT_FOUND("unknown product: %llu", article);
default:
- warning("[internal error: %d]".printf(rc));
- return -1;
+ throw new DatabaseError.INTERNAL_ERROR("internal error: %d", rc);
}
}
- public Price get_product_price(int user, uint64 article) {
+ public Price get_product_price(int user, uint64 article) throws DatabaseError {
int64 timestamp = (new DateTime.now_utc()).to_unix();
bool member = user != 0;
@@ -473,15 +386,13 @@ public class Database {
else
return statements["price"].column_int(1);
case Sqlite.DONE:
- write_to_log("unbekanntes Produkt: %llu\n", article);
- return 0;
+ throw new DatabaseError.PRODUCT_NOT_FOUND("unknown product: %llu", article);
default:
- write_to_log("[internal error: %d]\n", rc);
- return 0;
+ throw new DatabaseError.INTERNAL_ERROR("internal error: %d", rc);
}
}
- public bool undo(int32 user) {
+ public bool undo(int32 user) throws DatabaseError {
uint64 pid = 0;
int rc = 0;
@@ -496,10 +407,9 @@ public class Database {
write_to_log("Remove purchase of %s", pname);
break;
case Sqlite.DONE:
- write_to_log("Error: undo not possible without purchases");
- return false;
+ throw new DatabaseError.PRODUCT_NOT_FOUND("undo not possible without purchases");
default:
- error("[internal error: %d]".printf(rc));
+ throw new DatabaseError.INTERNAL_ERROR("internal error: %d", rc);
}
statements["undo"].reset();
@@ -507,42 +417,37 @@ public class Database {
rc = statements["undo"].step();
if(rc != Sqlite.DONE)
- error("[internal error: %d]".printf(rc));
+ throw new DatabaseError.INTERNAL_ERROR("internal error: %d", rc);
return true;
}
- public bool restock(int user, uint64 product, uint amount, uint price, int supplier, int64 best_before_date) {
- if(user > 0) {
- int rc = 0;
- int64 timestamp = (new DateTime.now_utc()).to_unix();
-
- statements["stock"].reset();
- statements["stock"].bind_int(1, user);
- statements["stock"].bind_text(2, @"$product");
- statements["stock"].bind_text(3, @"$amount");
- statements["stock"].bind_text(4, @"$price");
- statements["stock"].bind_int64(5, timestamp);
- if(supplier > 0)
- statements["stock"].bind_int(6, supplier);
- else
- statements["stock"].bind_null(6);
- if(best_before_date > 0)
- statements["stock"].bind_int64(7, best_before_date);
- else
- statements["stock"].bind_null(7);
-
- rc = statements["stock"].step();
- if(rc != Sqlite.DONE)
- error("[internal error: %d]".printf(rc));
+ public void restock(int user, uint64 product, uint amount, uint price, int supplier, int64 best_before_date) throws DatabaseError {
+ int rc = 0;
+ int64 timestamp = (new DateTime.now_utc()).to_unix();
- return true;
- }
+ statements["stock"].reset();
+ statements["stock"].bind_int(1, user);
+ statements["stock"].bind_text(2, @"$product");
+ statements["stock"].bind_text(3, @"$amount");
+ statements["stock"].bind_text(4, @"$price");
+ statements["stock"].bind_int64(5, timestamp);
+ if(supplier > 0)
+ statements["stock"].bind_int(6, supplier);
+ else
+ statements["stock"].bind_null(6);
+ if(best_before_date > 0)
+ statements["stock"].bind_int64(7, best_before_date);
+ else
+ statements["stock"].bind_null(7);
- return false;
+ rc = statements["stock"].step();
+
+ if(rc != Sqlite.DONE)
+ throw new DatabaseError.INTERNAL_ERROR("internal error: %d", rc);
}
- public bool new_product(uint64 id, string name, int memberprice, int guestprice) {
+ public void new_product(uint64 id, string name, int memberprice, int guestprice) throws DatabaseError {
statements["product_create"].reset();
statements["product_create"].bind_text(1, @"$id");
statements["product_create"].bind_text(2, name);
@@ -550,14 +455,13 @@ public class Database {
int rc = statements["product_create"].step();
if(rc != Sqlite.DONE) {
- warning("[internal error: %d]".printf(rc));
- return false;
+ throw new DatabaseError.INTERNAL_ERROR("internal error: %d", rc);
}
- return new_price(id, 0, memberprice, guestprice);
+ new_price(id, 0, memberprice, guestprice);
}
- public bool new_price(uint64 product, int64 timestamp, int memberprice, int guestprice) {
+ public void new_price(uint64 product, int64 timestamp, int memberprice, int guestprice) throws DatabaseError {
statements["price_create"].reset();
statements["price_create"].bind_text(1, @"$product");
statements["price_create"].bind_int64(2, timestamp);
@@ -566,11 +470,8 @@ public class Database {
int rc = statements["price_create"].step();
if(rc != Sqlite.DONE) {
- warning("[internal error: %d]".printf(rc));
- return false;
+ throw new DatabaseError.INTERNAL_ERROR("internal error: %d", rc);
}
-
- return true;
}
public bool check_user_password(int32 user, string password) {
@@ -587,7 +488,7 @@ public class Database {
}
}
- public void set_user_password(int32 user, string password) {
+ public void set_user_password(int32 user, string password) throws DatabaseError {
var pwhash = Checksum.compute_for_string(ChecksumType.SHA256, password);
int rc;
@@ -596,7 +497,7 @@ public class Database {
statements["user_auth_create"].bind_int(1, user);
rc = statements["user_auth_create"].step();
if(rc != Sqlite.DONE)
- error("[internal error: %d]".printf(rc));
+ throw new DatabaseError.INTERNAL_ERROR("internal error: %d", rc);
/* set password */
statements["password_set"].reset();
@@ -604,36 +505,37 @@ public class Database {
statements["password_set"].bind_int(2, user);
rc = statements["password_set"].step();
if(rc != Sqlite.DONE)
- error("[internal error: %d]".printf(rc));
+ throw new DatabaseError.INTERNAL_ERROR("internal error: %d", rc);
}
- public void set_sessionid(int user, string sessionid) {
+ public void set_sessionid(int user, string sessionid) throws DatabaseError {
statements["session_set"].reset();
statements["session_set"].bind_text(1, sessionid);
statements["session_set"].bind_int(2, user);
int rc = statements["session_set"].step();
if(rc != Sqlite.DONE)
- error("[internal error: %d]".printf(rc));
+ throw new DatabaseError.INTERNAL_ERROR("internal error: %d", rc);
}
- public int get_user_by_sessionid(string sessionid) throws WebSessionError {
+ public int get_user_by_sessionid(string sessionid) throws DatabaseError {
statements["session_get"].reset();
statements["session_get"].bind_text(1, sessionid);
if(statements["session_get"].step() == Sqlite.ROW) {
return statements["session_get"].column_int(0);
} else {
- throw new WebSessionError.SESSION_NOT_FOUND("No such session available in database!");
+ throw new DatabaseError.SESSION_NOT_FOUND("No such session available in database!");
}
}
- public UserInfo get_user_info(int user) {
+ public UserInfo get_user_info(int user) throws DatabaseError {
var result = UserInfo();
statements["userinfo"].reset();
statements["userinfo"].bind_int(1, user);
+ int rc = statements["userinfo"].step();
- if(statements["userinfo"].step() == Sqlite.ROW) {
+ if(rc == Sqlite.ROW) {
result.id = user;
result.firstname = statements["userinfo"].column_text(0);
result.lastname = statements["userinfo"].column_text(1);
@@ -643,12 +545,16 @@ public class Database {
result.postcode = statements["userinfo"].column_int(5);
result.city = statements["userinfo"].column_text(6);
result.pgp = statements["userinfo"].column_text(7);
+ } else if(rc == Sqlite.DONE) {
+ throw new DatabaseError.USER_NOT_FOUND("user not found");
+ } else {
+ throw new DatabaseError.INTERNAL_ERROR("internal error: %d", rc);
}
return result;
}
- public UserAuth get_user_auth(int user) {
+ public UserAuth get_user_auth(int user) throws DatabaseError {
var result = UserAuth();
result.id = user;
result.disabled = false;
@@ -656,27 +562,33 @@ public class Database {
statements["userauth"].reset();
statements["userauth"].bind_int(1, user);
- if(statements["userauth"].step() == Sqlite.ROW) {
+ int rc = statements["userauth"].step();
+
+ if(rc == Sqlite.ROW) {
result.disabled = statements["userauth"].column_int(0) == 1;
result.superuser = statements["userauth"].column_int(1) == 1;
+ } else if(rc == Sqlite.DONE) {
+ throw new DatabaseError.USER_NOT_FOUND("user not found");
+ } else {
+ throw new DatabaseError.INTERNAL_ERROR("internal error: %d", rc);
}
return result;
}
- public string get_username(int user) throws WebSessionError {
+ public string get_username(int user) throws DatabaseError {
statements["username"].reset();
statements["username"].bind_int(1, user);
if(statements["username"].step() == Sqlite.ROW) {
return statements["username"].column_text(0)+" "+statements["username"].column_text(1);
} else {
- throw new WebSessionError.USER_NOT_FOUND("No such user available in database!");
+ throw new DatabaseError.USER_NOT_FOUND("No such user available in database!");
}
}
- public Gee.List<InvoiceEntry?> get_invoice(int user, int64 from=0, int64 to=-1) {
- var result = new Gee.ArrayList<InvoiceEntry?>();
+ public InvoiceEntry[] get_invoice(int user, int64 from=0, int64 to=-1) throws DatabaseError {
+ InvoiceEntry[] result = {};
if(to == -1) {
to = time_t();
@@ -686,37 +598,44 @@ public class Database {
statements["invoice"].bind_int(1, user);
statements["invoice"].bind_int64(2, from);
statements["invoice"].bind_int64(3, to);
+ int rc = statements["invoice"].step();
- while(statements["invoice"].step() == Sqlite.ROW) {
+ while(rc == Sqlite.ROW) {
InvoiceEntry entry = {};
entry.timestamp = statements["invoice"].column_int64(0);
entry.product.ean = uint64.parse(statements["invoice"].column_text(1));
entry.product.name = statements["invoice"].column_text(2);
entry.price = statements["invoice"].column_int(3);
- result.add(entry);
+ result += entry;
+
+ rc = statements["invoice"].step();
+ }
+
+ if(rc != Sqlite.DONE) {
+ throw new DatabaseError.INTERNAL_ERROR("internal error: %d", rc);
}
return result;
}
- public DateTime get_first_purchase(int user) {
+ public int64 get_first_purchase(int user) {
statements["purchase_first"].reset();
statements["purchase_first"].bind_int(1, user);
if(statements["purchase_first"].step() == Sqlite.ROW)
- return new DateTime.from_unix_utc(statements["purchase_first"].column_int64(0));
+ return statements["purchase_first"].column_int64(0);
else
- return new DateTime.from_unix_utc(0);
+ return 0;
}
- public DateTime get_last_purchase(int user) {
+ public int64 get_last_purchase(int user) {
statements["purchase_last"].reset();
statements["purchase_last"].bind_int(1, user);
if(statements["purchase_last"].step() == Sqlite.ROW)
- return new DateTime.from_unix_utc(statements["purchase_last"].column_int64(0));
+ return statements["purchase_last"].column_int64(0);
else
- return new DateTime.from_unix_utc(0);
+ return 0;
}
public StatsInfo get_stats_info() {
@@ -794,17 +713,17 @@ public class Database {
return result;
}
- public Gee.List<int> get_member_ids() {
- var result = new Gee.ArrayList<int>();
+ public int[] get_member_ids() {
+ int[] result = {};
statements["user_get_ids"].reset();
while(statements["user_get_ids"].step() == Sqlite.ROW)
- result.add(statements["user_get_ids"].column_int(0));
+ result += statements["user_get_ids"].column_int(0);
return result;
}
- public void user_disable(int user, bool value) {
+ public void user_disable(int user, bool value) throws DatabaseError {
int rc;
/* create user auth line if not existing */
@@ -812,7 +731,7 @@ public class Database {
statements["user_auth_create"].bind_int(1, user);
rc = statements["user_auth_create"].step();
if(rc != Sqlite.DONE)
- error("[internal error: %d]".printf(rc));
+ throw new DatabaseError.INTERNAL_ERROR("internal error: %d", rc);
/* set disabled flag */
statements["user_disable"].reset();
@@ -820,10 +739,10 @@ public class Database {
statements["user_disable"].bind_int(2, user);
rc = statements["user_disable"].step();
if(rc != Sqlite.DONE)
- error("[internal error: %d]".printf(rc));
+ throw new DatabaseError.INTERNAL_ERROR("internal error: %d", rc);
}
- public void user_replace(UserInfo u) {
+ public void user_replace(UserInfo u) throws DatabaseError {
statements["user_replace"].reset();
statements["user_replace"].bind_int(1, u.id);
statements["user_replace"].bind_text(2, u.email);
@@ -837,13 +756,24 @@ public class Database {
int rc = statements["user_replace"].step();
if(rc != Sqlite.DONE)
- error("[internal error: %d]".printf(rc));
+ throw new DatabaseError.INTERNAL_ERROR("internal error: %d", rc);
}
- public bool user_is_disabled(int user) {
+ public bool user_is_disabled(int user) throws DatabaseError {
return get_user_auth(user).disabled;
}
+ public bool user_exists(int user) throws DatabaseError {
+ if(user in get_member_ids())
+ return true;
+ return false;
+ }
+
+ public bool user_equals(UserInfo u) throws DatabaseError {
+ var dbu = get_user_info(u.id);
+ return u.equals(dbu);
+ }
+
public int64 get_timestamp_of_last_purchase() {
statements["last_timestamp"].reset();
if(statements["last_timestamp"].step() != Sqlite.ROW)
@@ -851,10 +781,10 @@ public class Database {
return statements["last_timestamp"].column_int64(0);
}
- public Gee.List<Supplier?> get_supplier_list() {
- var result = new Gee.ArrayList<Supplier?>();
- statements["supplier_list"].reset();
+ public Supplier[] get_supplier_list() {
+ Supplier[] result = {};
+ statements["supplier_list"].reset();
while(statements["supplier_list"].step() == Sqlite.ROW) {
Supplier entry = {
statements["supplier_list"].column_int64(0),
@@ -866,7 +796,7 @@ public class Database {
statements["supplier_list"].column_text(6)
};
- result.add(entry);
+ result += entry;
}
return result;
@@ -899,7 +829,7 @@ public class Database {
return result;
}
- public bool add_supplier(string name, string postal_code, string city, string street, string phone, string website) {
+ public void add_supplier(string name, string postal_code, string city, string street, string phone, string website) throws DatabaseError {
statements["supplier_add"].reset();
statements["supplier_add"].bind_text(1, name);
statements["supplier_add"].bind_text(2, postal_code);
@@ -910,10 +840,7 @@ public class Database {
int rc = statements["supplier_add"].step();
if(rc != Sqlite.DONE) {
- warning("[internal error: %d]".printf(rc));
- return false;
+ throw new DatabaseError.INTERNAL_ERROR("internal error: %d", rc);
}
-
- return true;
}
}
diff --git a/src/database/db-interface.vala b/src/database/db-interface.vala
new file mode 100644
index 0000000..da95eb7
--- /dev/null
+++ b/src/database/db-interface.vala
@@ -0,0 +1,148 @@
+/* Copyright 2013, Sebastian Reichel <sre@ring0.de>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+[DBus (name = "io.mainframe.shopsystem.Database")]
+public interface Database : Object {
+ public abstract StockEntry[] get_stock() throws IOError;
+ public abstract PriceEntry[] get_prices(uint64 product) throws IOError;
+ public abstract RestockEntry[] get_restocks(uint64 product) throws IOError;
+ public abstract bool buy(int32 user, uint64 article) throws IOError, DatabaseError;
+ public abstract string get_product_name(uint64 article) throws IOError, DatabaseError;
+ public abstract int get_product_amount(uint64 article) throws IOError, DatabaseError;
+ public abstract Price get_product_price(int user, uint64 article) throws IOError, DatabaseError;
+ public abstract bool undo(int32 user) throws IOError, DatabaseError;
+ public abstract bool restock(int user, uint64 product, uint amount, uint price, int supplier, int64 best_before_date) throws IOError, DatabaseError;
+ public abstract bool new_product(uint64 id, string name, int memberprice, int guestprice) throws IOError, DatabaseError;
+ public abstract bool new_price(uint64 product, int64 timestamp, int memberprice, int guestprice) throws IOError, DatabaseError;
+ public abstract bool check_user_password(int32 user, string password) throws IOError;
+ public abstract void set_user_password(int32 user, string password) throws IOError, DatabaseError;
+ public abstract void set_sessionid(int user, string sessionid) throws IOError, DatabaseError;
+ public abstract int get_user_by_sessionid(string sessionid) throws IOError, DatabaseError;
+ public abstract UserInfo get_user_info(int user) throws IOError, DatabaseError;
+ public abstract UserAuth get_user_auth(int user) throws IOError, DatabaseError;
+ public abstract string get_username(int user) throws IOError, DatabaseError;
+ public abstract InvoiceEntry[] get_invoice(int user, int64 from=0, int64 to=-1) throws IOError, DatabaseError;
+ public abstract int64 get_first_purchase(int user) throws IOError;
+ public abstract int64 get_last_purchase(int user) throws IOError;
+ public abstract StatsInfo get_stats_info() throws IOError;
+ public abstract int[] get_member_ids() throws IOError;
+ public abstract void user_disable(int user, bool value) throws IOError, DatabaseError;
+ public abstract void user_replace(UserInfo u) throws IOError, DatabaseError;
+ public abstract bool user_is_disabled(int user) throws IOError, DatabaseError;
+ public abstract bool user_exists(int user) throws IOError, DatabaseError;
+ public abstract bool user_equals(UserInfo u) throws IOError, DatabaseError;
+ public abstract int64 get_timestamp_of_last_purchase() throws IOError;
+ public abstract Supplier[] get_supplier_list() throws IOError;
+ public abstract Supplier get_supplier(int id) throws IOError;
+ public abstract bool add_supplier(string name, string postal_code, string city, string street, string phone, string website) throws IOError, DatabaseError;
+}
+
+public struct StockEntry {
+ public string id;
+ public string name;
+ public int amount;
+ public string memberprice;
+ public string guestprice;
+}
+
+public struct PriceEntry {
+ public int64 valid_from;
+ public Price memberprice;
+ public Price guestprice;
+}
+
+public struct RestockEntry {
+ public int64 timestamp;
+ public int amount;
+ public string price;
+ public int supplier;
+ public int64 best_before_date;
+}
+
+public struct Supplier {
+ public int64 id;
+ public string name;
+ public string postal_code;
+ public string city;
+ public string street;
+ public string phone;
+ public string website;
+}
+
+public struct UserInfo {
+ public int id;
+ public string firstname;
+ public string lastname;
+ public string email;
+ public string gender;
+ public string street;
+ public int postcode;
+ public string city;
+ public string pgp;
+
+ public bool equals(UserInfo x) {
+ if(id != x.id) return false;
+ if(firstname != x.firstname) return false;
+ if(lastname != x.lastname) return false;
+ if(email != x.email) return false;
+ if(gender != x.gender) return false;
+ if(street != x.street) return false;
+ if(postcode != x.postcode) return false;
+ if(city != x.city) return false;
+ if(pgp != x.pgp) return false;
+
+ return true;
+ }
+}
+
+public struct UserAuth {
+ public int id;
+ public bool disabled;
+ public bool superuser;
+}
+
+public struct Product {
+ public uint64 ean;
+ public string name;
+}
+
+public struct InvoiceEntry {
+ public int64 timestamp;
+ Product product;
+ Price price;
+}
+
+public struct StatsInfo {
+ public int count_articles;
+ public int count_users;
+ public Price stock_value;
+ public Price sales_total;
+ public Price profit_total;
+ public Price sales_today;
+ public Price profit_today;
+ public Price sales_this_month;
+ public Price profit_this_month;
+ public Price sales_per_day;
+ public Price profit_per_day;
+ public Price sales_per_month;
+ public Price profit_per_month;
+}
+
+public errordomain DatabaseError {
+ INTERNAL_ERROR,
+ PRODUCT_NOT_FOUND,
+ SESSION_NOT_FOUND,
+ USER_NOT_FOUND
+}
diff --git a/src/database/main.vala b/src/database/main.vala
new file mode 100644
index 0000000..676e960
--- /dev/null
+++ b/src/database/main.vala
@@ -0,0 +1,44 @@
+/* Copyright 2013, Sebastian Reichel <sre@ring0.de>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+public static void write_to_log(string message, ...) {
+ /* TODO: send message via DBus? Replace some write_to_log by throwing an error? */
+}
+
+DataBase db;
+
+public static int main(string[] args) {
+ db = new DataBase("../../shop.db");
+
+ Bus.own_name(
+ BusType.SESSION,
+ "io.mainframe.shopsystem.Database",
+ BusNameOwnerFlags.NONE,
+ on_bus_aquired,
+ () => {},
+ () => stderr.printf("Could not aquire name\n"));
+
+ new MainLoop().run();
+
+ return 0;
+}
+
+void on_bus_aquired(DBusConnection con) {
+ try {
+ con.register_object("/io/mainframe/shopsystem/database", db);
+ } catch(IOError e) {
+ stderr.printf("Could not register service\n");
+ }
+}
diff --git a/src/main.vala b/src/main.vala
deleted file mode 100644
index 67f00ff..0000000
--- a/src/main.vala
+++ /dev/null
@@ -1,131 +0,0 @@
-/* Copyright 2012, Sebastian Reichel <sre@ring0.de>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-public Device dev;
-public Database db;
-public AudioPlayer audio;
-public CSVMemberFile csvimport;
-public ScannerSession localsession;
-public MainLoop loop;
-public PGPKeyArchive pgp;
-public KeyFile cfg;
-public CursesUI ui;
-
-const OptionEntry[] option_entries = {
- { "version", 'v', OptionFlags.IN_MAIN, OptionArg.NONE, ref opt_version, "output version information and exit", null },
- {null}
-};
-
-/* parameters */
-static bool opt_version;
-
-public static int main(string[] args) {
- /* parse parameters from shell */
- var context = new OptionContext("- KtT Shop System");
- context.set_help_enabled(true);
- context.add_main_entries(option_entries, "shop");
- context.add_group(Gst.init_get_option_group());
-
- try {
- context.parse(ref args);
- } catch(OptionError e) {
- stderr.puts(e.message + "\n");
- return 1;
- }
-
- if(opt_version) {
- stdout.puts("KtT Shop System 0.1\n");
- return 0;
- }
-
- /* handle unix signals */
- Unix.signal_add(Posix.SIGTERM, handle_signals);
- Unix.signal_add(Posix.SIGINT, handle_signals);
-
- try {
- cfg = new KeyFile();
- cfg.load_from_file("ktt-shopsystem.cfg", KeyFileFlags.NONE);
- } catch(Error e) {
- error("Could not load configuration file: %s", e.message);
- }
-
- string devicefile = "";
- try {
- devicefile = cfg.get_string("SERIAL", "device");
- } catch(KeyFileError e) {
- stderr.puts("Please specify serial device in the configuration file!\n");
- return 1;
- }
-
- dev = new Device(devicefile, 9600, 8, 1);
- db = new Database("shop.db");
- audio = new AudioPlayer();
- loop = new MainLoop();
- localsession = new ScannerSession();
-
- pgp = new PGPKeyArchive(cfg);
-
- dev.received_barcode.connect((data) => {
- if(localsession.interpret(data))
- dev.blink(10);
- });
-
- ui = new CursesUI();
-
- while(!check_valid_time()) {
- write_to_log("Invalid System Time! Retry in 1 minute...");
- Posix.sleep(60);
- }
-
- write_to_log("KtT Shop System has been started");
- audio.play_system("startup.ogg");
-
- /* attach webserver to mainloop */
- new WebServer();
-
- /* run mainloop */
- loop.run();
-
- write_to_log("Stopping Shop System");
- audio.play_system("shutdown.ogg");
-
- /* we need to run the mainloop to play audio */
- audio.end_of_stream.connect(() => { loop.quit(); });
- loop.run();
-
- /* explicitly call destructors */
- dev = null;
- db = null;
- audio = null;
- ui.exit();
-
- return 0;
-}
-
-public bool check_valid_time() {
- return time_t() > db.get_timestamp_of_last_purchase();
-}
-
-public void write_to_log(string format, ...) {
- var arguments = va_list();
- var message = format.vprintf(arguments);
-
- ui.log(message);
-}
-
-bool handle_signals() {
- loop.quit();
- return false;
-}
diff --git a/src/pdf-invoice/Makefile b/src/pdf-invoice/Makefile
index 2a5d2a4..cc6db94 100644
--- a/src/pdf-invoice/Makefile
+++ b/src/pdf-invoice/Makefile
@@ -1,9 +1,12 @@
all: pdf-invoice
-pdf-invoice: pdf-invoice.vala ../price.vapi
- valac --pkg pangocairo --pkg posix --pkg gio-2.0 $^
+pdf-invoice: main.vala pdf-invoice.vala pdf-invoice-interface.vala ../price.vapi
+ valac -g -o $@ --pkg pangocairo --pkg librsvg-2.0 --pkg posix --pkg gdk-2.0 --pkg gio-2.0 $^
+
+test: pdf-invoice-interface.vala test.vala ../price.vapi
+ valac -o $@ --pkg gio-2.0 $^
clean:
- rm -rf pdf-invoice
+ rm -rf pdf-invoice test
.PHONY: all clean
diff --git a/src/pdf-invoice/main.vala b/src/pdf-invoice/main.vala
new file mode 100644
index 0000000..76b03c6
--- /dev/null
+++ b/src/pdf-invoice/main.vala
@@ -0,0 +1,36 @@
+/* Copyright 2013, Sebastian Reichel <sre@ring0.de>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+public static int main(string[] args) {
+ Bus.own_name(
+ BusType.SESSION,
+ "io.mainframe.shopsystem.InvoicePDF",
+ BusNameOwnerFlags.NONE,
+ on_bus_aquired,
+ () => {},
+ () => stderr.printf("Could not aquire name\n"));
+
+ new MainLoop().run();
+
+ return 0;
+}
+
+void on_bus_aquired(DBusConnection conn) {
+ try {
+ conn.register_object("/io/mainframe/shopsystem/invoicepdf", new InvoicePDF());
+ } catch(IOError e) {
+ stderr.printf("Could not register service\n");
+ }
+}
diff --git a/src/pdf-invoice/pdf-invoice-interface.vala b/src/pdf-invoice/pdf-invoice-interface.vala
new file mode 100644
index 0000000..d2c04d9
--- /dev/null
+++ b/src/pdf-invoice/pdf-invoice-interface.vala
@@ -0,0 +1,54 @@
+/* Copyright 2013, Sebastian Reichel <sre@ring0.de>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+[DBus (name = "io.mainframe.shopsystem.InvoicePDFError")]
+public errordomain InvoicePDFError {
+ /* missing invoice data */
+ NO_INVOICE_DATA,
+ NO_INVOICE_DATE,
+ NO_INVOICE_ID,
+ NO_INVOICE_RECIPIENT,
+
+ /* data not supported by renderer */
+ ARTICLE_NAME_TOO_LONG,
+ PRICE_TOO_HIGH,
+ TOO_FAR_IN_THE_FUTURE
+}
+
+public struct InvoiceRecipient {
+ public string firstname;
+ public string lastname;
+ public string street;
+ public string postal_code;
+ public string city;
+ public string gender;
+}
+
+public struct InvoiceEntry {
+ int timestamp;
+ string article;
+ Price price;
+}
+
+[DBus (name = "io.mainframe.shopsystem.InvoicePDF")]
+public interface PDFInvoice : Object {
+ public abstract string invoice_id { set; owned get; }
+ public abstract int64 invoice_date { set; owned get; }
+ public abstract InvoiceRecipient invoice_recipient { set; owned get; }
+ public abstract InvoiceEntry[] invoice_entries { set; owned get; }
+
+ public abstract uint8[] generate() throws IOError, InvoicePDFError;
+ public abstract void clear() throws IOError;
+}
diff --git a/src/pdf-invoice/pdf-invoice.vala b/src/pdf-invoice/pdf-invoice.vala
index 92598f6..095dcc6 100644
--- a/src/pdf-invoice/pdf-invoice.vala
+++ b/src/pdf-invoice/pdf-invoice.vala
@@ -13,35 +13,6 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-[DBus (name = "io.mainframe.shopsystem.InvoicePDFError")]
-public errordomain InvoicePDFError {
- /* missing invoice data */
- NO_INVOICE_DATA,
- NO_INVOICE_DATE,
- NO_INVOICE_ID,
- NO_INVOICE_RECIPIENT,
-
- /* data not supported by renderer */
- ARTICLE_NAME_TOO_LONG,
- PRICE_TOO_HIGH,
- TOO_FAR_IN_THE_FUTURE
-}
-
-public struct InvoiceRecipient {
- public string firstname;
- public string lastname;
- public string street;
- public string postal_code;
- public string city;
- public string gender;
-}
-
-public struct InvoiceEntry {
- int timestamp;
- string article;
- Price price;
-}
-
[DBus (name = "io.mainframe.shopsystem.InvoicePDF")]
public class InvoicePDF {
/* A4 sizes (in points, 72 DPI) */
@@ -49,10 +20,10 @@ public class InvoicePDF {
private const double height = 841.88976; /* 297mm */
/* invoice content, which should appear in the PDF */
- public string invoice_id { set; get; }
+ public string invoice_id { set; owned get; }
public int64 invoice_date { set; get; }
- public InvoiceRecipient invoice_recipient { set; get; }
- public InvoiceEntry[] invoice_entries { set; get; }
+ public InvoiceRecipient invoice_recipient { set; owned get; }
+ public InvoiceEntry[] invoice_entries { set; owned get; }
/* pdf data */
private uint8[] data;
@@ -77,29 +48,27 @@ public class InvoicePDF {
};
public InvoicePDF() {
+ clear();
+ }
+
+ private void render_svg(Cairo.Context ctx, string file) {
+ var svg = new Rsvg.Handle.from_file(file);
+ svg.render_cairo(ctx);
}
private void draw_footer(Cairo.Context ctx) {
- /* TODO: get path from config file, support svg */
- var footer = new Cairo.ImageSurface.from_png("../../invoice/footer-line.png");
- ctx.set_source_surface(footer, 0, 817);
- ctx.paint();
+ ctx.save();
+ ctx.translate(-20, 818);
+ ctx.scale(1.42, 1.42);
+ render_svg(ctx, "../../invoice/footer-line.svg");
+ ctx.restore();
}
private void draw_logo(Cairo.Context ctx) {
- /* TODO: get path from config file, support svg */
- var logo = new Cairo.ImageSurface.from_png("../../invoice/logo.png");
-
- var pattern = new Cairo.Pattern.for_surface(logo);
- Cairo.Matrix scaler;
- pattern.get_matrix(out scaler);
- scaler.scale(1.41,1.41);
- scaler.translate(-364.5,-22.5);
- pattern.set_matrix(scaler);
- pattern.set_filter(Cairo.Filter.BEST);
-
- ctx.set_source(pattern);
- ctx.paint();
+ ctx.save();
+ ctx.translate(366,25);
+ render_svg(ctx, "../../invoice/logo.svg");
+ ctx.restore();
}
private void draw_address(Cairo.Context ctx) {
@@ -661,29 +630,14 @@ public class InvoicePDF {
public void clear() {
invoice_date = 0;
invoice_id = "";
- invoice_recipient = {};
+ invoice_recipient = {
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ };
invoice_entries = null;
}
}
-
-public static int main(string[] args) {
- Bus.own_name(
- BusType.SESSION,
- "io.mainframe.shopsystem.InvoicePDF",
- BusNameOwnerFlags.NONE,
- on_bus_aquired,
- () => {},
- () => stderr.printf ("Could not aquire name\n"));
-
- new MainLoop ().run ();
-
- return 0;
-}
-
-void on_bus_aquired(DBusConnection conn) {
- try {
- conn.register_object ("/io/mainframe/invoicepdf", new InvoicePDF());
- } catch (IOError e) {
- stderr.printf ("Could not register service\n");
- }
-}
diff --git a/src/pdf-invoice/test.vala b/src/pdf-invoice/test.vala
new file mode 100644
index 0000000..f9d21f6
--- /dev/null
+++ b/src/pdf-invoice/test.vala
@@ -0,0 +1,47 @@
+/* Copyright 2013, Sebastian Reichel <sre@ring0.de>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+public static int main(string args[]) {
+ PDFInvoice invoice = Bus.get_proxy_sync(BusType.SESSION, "io.mainframe.shopsystem.InvoicePDF", "/io/mainframe/shopsystem/invoicepdf");
+
+ InvoiceRecipient r = {
+ "Max",
+ "Mustermann",
+ "Foobar Straße 42",
+ "31337",
+ "Entenhausen",
+ "masculinum"
+ };
+
+ InvoiceEntry e1 = {
+ 1364271520,
+ "Club Mate",
+ 2342
+ };
+
+ /* set invoice data */
+ invoice.invoice_id = "TEST";
+ invoice.invoice_date = 1364271524;
+ invoice.invoice_recipient = r;
+ invoice.invoice_entries = {e1};
+
+ /* generate pdf */
+ var pdfdata = invoice.generate();
+
+ /* write pdf into file */
+ FileUtils.set_contents("test.pdf", (string) pdfdata, pdfdata.length);
+
+ return 0;
+}
diff --git a/src/pgp/Makefile b/src/pgp/Makefile
new file mode 100644
index 0000000..6bcb535
--- /dev/null
+++ b/src/pgp/Makefile
@@ -0,0 +1,9 @@
+all: pgp
+
+pgp: main.vala pgp.vala pgp-interface.vala ../config/config-interface.vala
+ valac -o $@ --vapidir ../../vapi -X -lgpgme --pkg gpgme --pkg gio-2.0 --pkg libarchive $^
+
+clean:
+ rm -rf pgp
+
+.PHONY: all clean
diff --git a/src/pgp/main.vala b/src/pgp/main.vala
new file mode 100644
index 0000000..f95b6f7
--- /dev/null
+++ b/src/pgp/main.vala
@@ -0,0 +1,53 @@
+/* Copyright 2013, Sebastian Reichel <sre@ring0.de>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+public static void write_to_log(string message, ...) {
+ /* TODO: send message via DBus? Replace some write_to_log by throwing an error? */
+}
+
+PGPKeyArchive pgp;
+Config cfg;
+
+public static int main(string[] args) {
+ try {
+ cfg = Bus.get_proxy_sync(BusType.SESSION, "io.mainframe.shopsystem.Config", "/io/mainframe/shopsystem/config");
+ pgp = new PGPKeyArchive(cfg.get_string("PGP", "keyring"));
+ } catch(IOError e) {
+ error("IOError: %s\n", e.message);
+ } catch(KeyFileError e) {
+ error("Config Error: %s\n", e.message);
+ }
+
+
+ Bus.own_name(
+ BusType.SESSION,
+ "io.mainframe.shopsystem.PGP",
+ BusNameOwnerFlags.NONE,
+ on_bus_aquired,
+ () => {},
+ () => stderr.printf("Could not aquire name\n"));
+
+ new MainLoop().run();
+
+ return 0;
+}
+
+void on_bus_aquired(DBusConnection con) {
+ try {
+ con.register_object("/io/mainframe/shopsystem/pgp", pgp);
+ } catch(IOError e) {
+ stderr.printf("Could not register service\n");
+ }
+}
diff --git a/src/pgp/pgp-interface.vala b/src/pgp/pgp-interface.vala
new file mode 100644
index 0000000..62bfe67
--- /dev/null
+++ b/src/pgp/pgp-interface.vala
@@ -0,0 +1,21 @@
+/* Copyright 2013, Sebastian Reichel <sre@ring0.de>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+[DBus (name = "io.mainframe.shopsystem.PGP")]
+public interface PGP : Object {
+ public abstract string[] import_archive(uint8[] data) throws IOError;
+ public abstract string[] list_keys() throws IOError;
+ public abstract string get_key(string fingerprint) throws IOError;
+}
diff --git a/src/admin.vala b/src/pgp/pgp.vala
index de123e1..bb48c61 100644
--- a/src/admin.vala
+++ b/src/pgp/pgp.vala
@@ -1,4 +1,4 @@
-/* Copyright 2012, Sebastian Reichel <sre@ring0.de>
+/* Copyright 2013, Sebastian Reichel <sre@ring0.de>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -13,88 +13,24 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-public class CSVMemberFile {
- private UserInfo[] members;
-
- public Gee.List<int> missing_unblocked_members() {
- var result = new Gee.ArrayList<int>();
- var dbusers = db.get_member_ids();
-
- foreach(var u in dbusers) {
- bool found=false;
- foreach(var m in members) {
- if(u == m.id) {
- found=true;
- break;
- }
- }
-
- if(!found) {
- if(!db.user_is_disabled(u))
- result.add(u);
- }
- }
-
- return result;
- }
-
- private string[] csv_split(string line) {
- return /;(?=(?:[^\"]*\"[^\"]*\")*(?![^\"]*\"))/.split(line);
- }
-
- private string csv_value(string value) {
- if(value[0] == '"' && value[value.length-1] == '"')
- return value.substring(1,value.length-2);
- else
- return value;
- }
-
- public CSVMemberFile(string data) {
- foreach(var line in data.split("\n")) {
- var linedata = csv_split(line);
- if(linedata.length >= 9) {
- var m = UserInfo();
- m.id = int.parse(csv_value(linedata[0]));
- m.email = csv_value(linedata[1]);
- m.firstname = csv_value(linedata[2]);
- m.lastname = csv_value(linedata[3]);
- m.street = csv_value(linedata[4]);
- m.postcode = int.parse(csv_value(linedata[5]));
- m.city = csv_value(linedata[6]);
- m.gender = csv_value(linedata[7]) == "m" ? "masculinum" : csv_value(linedata[7]) == "w" ? "femininum" : "unknown";
- m.pgp = csv_value(linedata[8]);
- if(csv_value(linedata[0]) != "EXTERNEMITGLIEDSNUMMER")
- members += m;
- }
- }
- }
-
- public UserInfo[] get_members() {
- return members;
- }
-}
-
+[DBus (name = "io.mainframe.shopsystem.PGP")]
public class PGPKeyArchive {
private string keyring;
private GPG.Context gpg;
- public PGPKeyArchive(KeyFile config) {
+ public PGPKeyArchive(string keyring) {
/* check version (important!) */
GPG.check_version();
/* initialize default context */
GPG.Context.Context(out gpg);
- try {
- keyring = config.get_string("PGP", "keyring");
-
- /* remove quotes */
- if(keyring.has_prefix("\"") && keyring.has_suffix("\""))
- keyring = keyring.substring(1,keyring.length-2);
- } catch(KeyFileError e) {
- write_to_log("KeyFileError: %s", e.message);
- return;
- }
+ /* TODO TODO TODO */
+#if 0
+ if(keyring.has_prefix("\"") && keyring.has_suffix("\""))
+ this.keyring = keyring.substring(1,keyring.length-2);
+#endif
+ this.keyring = keyring;
/* TODO: check existence of keyring */
diff --git a/src/scanner-session/Makefile b/src/scanner-session/Makefile
new file mode 100644
index 0000000..ea91d3a
--- /dev/null
+++ b/src/scanner-session/Makefile
@@ -0,0 +1,9 @@
+all: scanner-session
+
+scanner-session: main.vala scannersession.vala scannersession-interface.vala ../database/db-interface.vala ../serial-device/serial-device-interface.vala ../audio/audio-interface.vala ../price.vapi
+ valac -o $@ --pkg gio-2.0 $^
+
+clean:
+ rm -rf scanner-session
+
+.PHONY: all clean
diff --git a/src/scanner-session/main.vala b/src/scanner-session/main.vala
new file mode 100644
index 0000000..11562e1
--- /dev/null
+++ b/src/scanner-session/main.vala
@@ -0,0 +1,38 @@
+/* Copyright 2013, Sebastian Reichel <sre@ring0.de>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+ScannerSessionImplementation session;
+
+public static int main(string[] args) {
+ Bus.own_name(
+ BusType.SESSION,
+ "io.mainframe.shopsystem.ScannerSession",
+ BusNameOwnerFlags.NONE,
+ on_bus_aquired,
+ () => {},
+ () => stderr.printf("Could not aquire name\n"));
+
+ new MainLoop().run();
+
+ return 0;
+}
+
+void on_bus_aquired(DBusConnection con) {
+ try {
+ con.register_object("/io/mainframe/shopsystem/scanner_session", session);
+ } catch(IOError e) {
+ stderr.printf("Could not register service\n");
+ }
+}
diff --git a/src/scanner-session/scannersession-interface.vala b/src/scanner-session/scannersession-interface.vala
new file mode 100644
index 0000000..0f81dd4
--- /dev/null
+++ b/src/scanner-session/scannersession-interface.vala
@@ -0,0 +1,25 @@
+/* Copyright 2013, Sebastian Reichel <sre@ring0.de>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+[DBus (name = "io.mainframe.shopsystem.ScannerSession")]
+public interface ScannerSession : Object {
+ public abstract signal void msg(MessageType type, string message);
+}
+
+public enum MessageType {
+ INFO,
+ WARNING,
+ ERROR
+}
diff --git a/src/scannersession.vala b/src/scanner-session/scannersession.vala
index 9dbe3d3..6926ba9 100644
--- a/src/scannersession.vala
+++ b/src/scanner-session/scannersession.vala
@@ -1,4 +1,4 @@
-/* Copyright 2012, Sebastian Reichel <sre@ring0.de>
+/* Copyright 2012-2013, Sebastian Reichel <sre@ring0.de>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -13,43 +13,45 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-public class ScannerSession {
- public int user {
- get;
- private set;
- default = 0;
- }
- public string name {
- get;
- private set;
- default = "Guest";
- }
- public bool logged_in {
- get;
- private set;
- default = false;
- }
- public bool disabled {
- get;
- private set;
- default = false;
+[DBus (name = "io.mainframe.shopsystem.ScannerSession")]
+public class ScannerSessionImplementation {
+ private int user = 0;
+ private string name = "Guest";
+ private bool logged_in = false;
+ private bool disabled = false;
+ private string theme = "beep";
+
+ private Database db;
+ private AudioPlayer audio;
+
+ public signal void msg(MessageType type, string message);
+
+ public ScannerSessionImplementation() {
+ try {
+ db = Bus.get_proxy_sync(BusType.SESSION, "io.mainframe.shopsystem.Database", "/io/mainframe/shopsystem/database");
+ audio = Bus.get_proxy_sync(BusType.SESSION, "io.mainframe.shopsystem.AudioPlayer", "/io/mainframe/shopsystem/audio");
+ } catch(IOError e) {
+ error("IOError: %s\n", e.message);
+ }
}
- public string theme {
- get;
- private set;
- default = "beep";
+
+ private void send_message(MessageType type, string format, ...) {
+ var arguments = va_list();
+ var message = format.vprintf(arguments);
+
+ msg(type, message);
}
- public void logout() {
+ private void logout() {
logged_in = false;
}
- public bool login(int user) {
+ private bool login(int user) {
this.user = user;
try {
this.name = db.get_username(user);
this.disabled = db.get_user_auth(user).disabled;
- } catch(WebSessionError e) {
+ } catch(DatabaseError e) {
return false;
}
this.logged_in = true;
@@ -58,10 +60,7 @@ public class ScannerSession {
return true;
}
- public ScannerSession() {
- }
-
- public bool interpret(string scannerdata) {
+ private bool interpret(string scannerdata) {
if(scannerdata.has_prefix("USER ")) {
string str_id = scannerdata.substring(5);
int32 id = int.parse(str_id);
@@ -69,43 +68,43 @@ public class ScannerSession {
/* check if scannerdata has valid format */
if(scannerdata != "USER %d".printf(id)) {
audio.play_system("error.ogg");
- write_to_log("Error: Invalid User ID: %s", scannerdata);
+ send_message(MessageType.ERROR, "Invalid User ID: %s", scannerdata);
return false;
}
if(logged_in) {
- write_to_log("Warning: Last user forgot to logout");
+ send_message(MessageType.WARNING, "Last user forgot to logout");
logout();
}
if(login(id)) {
audio.play_user(theme, "login");
- write_to_log("Login: %s (%d)", name, user);
+ send_message(MessageType.INFO, "Login: %s (%d)", name, user);
return true;
} else {
audio.play_system("error.ogg");
- write_to_log("Error: Login failed (User ID = %d)", id);
+ send_message(MessageType.ERROR, "Login failed (User ID = %d)", id);
return false;
}
} else if(scannerdata == "GUEST") {
if(logged_in) {
- write_to_log("Warning: Last user forgot to logout");
+ send_message(MessageType.WARNING, "Last user forgot to logout");
logout();
}
if(login(0)) {
audio.play_user(theme, "login");
- write_to_log("Login: %s (%d)", name, user);
+ send_message(MessageType.INFO, "Login: %s (%d)", name, user);
return true;
} else {
audio.play_system("error.ogg");
- write_to_log("Error: Login failed (User ID = 0)");
+ send_message(MessageType.ERROR, "Login failed (User ID = 0)");
return false;
}
} else if(scannerdata == "UNDO") {
if(!logged_in) {
audio.play_system("error.ogg");
- write_to_log("Error: Can't undo if not logged in!");
+ send_message(MessageType.ERROR, "Can't undo if not logged in!");
return false;
} else {
if(db.undo(user)) {
@@ -113,14 +112,14 @@ public class ScannerSession {
return true;
} else {
audio.play_user(theme, "error");
- write_to_log("Error: Couldn't undo last purchase!");
+ send_message(MessageType.ERROR, "Couldn't undo last purchase!");
return false;
}
}
} else if(scannerdata == "LOGOUT") {
if(logged_in) {
audio.play_user(theme, "logout");
- write_to_log("Logout!");
+ send_message(MessageType.INFO, "Logout!");
logout();
return true;
}
@@ -133,7 +132,7 @@ public class ScannerSession {
/* check if scannerdata has valid format */
if(scannerdata != "%llu".printf(id) && scannerdata != "%08llu".printf(id) && scannerdata != "%013llu".printf(id)) {
audio.play_user(theme, "error");
- write_to_log("Error: invalid product: %s", scannerdata);
+ send_message(MessageType.ERROR, "invalid product: %s", scannerdata);
return false;
}
@@ -144,19 +143,19 @@ public class ScannerSession {
var gprice = db.get_product_price(0, id);
audio.play_system("error.ogg");
- write_to_log(@"article info: $name (Member: $mprice €, Guest: $gprice €)");
- write_to_log("Error: Login required for purchase!");
+ send_message(MessageType.INFO, @"article info: $name (Member: $mprice €, Guest: $gprice €)");
+ send_message(MessageType.ERROR, "Login required for purchase!");
return false;
}
if(db.buy(user, id)) {
var price = db.get_product_price(user, id);
audio.play_user(theme, "purchase");
- write_to_log(@"article bought: $name ($price €)");
+ send_message(MessageType.INFO, @"article bought: $name ($price €)");
return true;
} else {
audio.play_user(theme, "error");
- write_to_log("Error: purchase failed!");
+ send_message(MessageType.ERROR, "purchase failed!");
return false;
}
}
diff --git a/src/serial-device/Makefile b/src/serial-device/Makefile
new file mode 100644
index 0000000..952b3a1
--- /dev/null
+++ b/src/serial-device/Makefile
@@ -0,0 +1,9 @@
+all: serial-device
+
+serial-device: main.vala serial-device.vala serial-device-interface.vala ../config/config-interface.vala
+ valac -o $@ --pkg linux --pkg posix --pkg gio-2.0 $^
+
+clean:
+ rm -rf serial-device
+
+.PHONY: all clean
diff --git a/src/serial-device/main.vala b/src/serial-device/main.vala
new file mode 100644
index 0000000..e338842
--- /dev/null
+++ b/src/serial-device/main.vala
@@ -0,0 +1,47 @@
+/* Copyright 2013, Sebastian Reichel <sre@ring0.de>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+Device dev;
+
+public static int main(string[] args) {
+ try {
+ Config cfg = Bus.get_proxy_sync(BusType.SESSION, "io.mainframe.shopsystem.Config", "/io/mainframe/shopsystem/config");
+ dev = new Device(cfg.get_string("SERIAL", "device"), 9600, 8, 1);
+ } catch(IOError e) {
+ error("IOError: %s\n", e.message);
+ } catch(KeyFileError e) {
+ error("Config Error: %s\n", e.message);
+ }
+
+ Bus.own_name(
+ BusType.SESSION,
+ "io.mainframe.shopsystem.SerialDevice",
+ BusNameOwnerFlags.NONE,
+ on_bus_aquired,
+ () => {},
+ () => stderr.printf("Could not aquire name\n"));
+
+ new MainLoop().run();
+
+ return 0;
+}
+
+void on_bus_aquired(DBusConnection con) {
+ try {
+ con.register_object("/io/mainframe/shopsystem/device", dev);
+ } catch(IOError e) {
+ stderr.printf("Could not register service\n");
+ }
+}
diff --git a/src/serial-device/serial-device-interface.vala b/src/serial-device/serial-device-interface.vala
new file mode 100644
index 0000000..572e810
--- /dev/null
+++ b/src/serial-device/serial-device-interface.vala
@@ -0,0 +1,20 @@
+/* Copyright 2013, Sebastian Reichel <sre@ring0.de>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+[DBus (name = "io.mainframe.shopsystem.SerialDevice")]
+public interface SerialDevice : Object {
+ public abstract signal void received_barcode(string barcode);
+ public abstract void blink(uint duration) throws IOError;
+}
diff --git a/src/device.vala b/src/serial-device/serial-device.vala
index 5d7fc09..76bb5b5 100644
--- a/src/device.vala
+++ b/src/serial-device/serial-device.vala
@@ -1,4 +1,4 @@
-/* Copyright 2012, Sebastian Reichel <sre@ring0.de>
+/* Copyright 2012-2013, Sebastian Reichel <sre@ring0.de>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -13,12 +13,13 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+[DBus (name = "io.mainframe.shopsystem.SerialDevice")]
public class Device {
private Posix.termios newtio;
private Posix.termios restoretio;
- public int fd=-1;
+ private int fd=-1;
private IOChannel io_read;
- public int byterate;
+ private int byterate;
private File lockfile;
public signal void received_barcode(string barcode);
diff --git a/src/ui/logo.vala b/src/ui/logo.vala
deleted file mode 100644
index 5a94422..0000000
--- a/src/ui/logo.vala
+++ /dev/null
@@ -1,30 +0,0 @@
-using Curses;
-
-public class Logo {
- Window win;
-
- public Logo() {
- win = new Window(8, COLS - 2, 0, 1);
- win.bkgdset(COLOR_PAIR(1) | Attribute.BOLD);
-
- win.addstr("\n");
- win.addstr(" _ ___ _____ ____ _ \n");
- win.addstr(" | |/ / ||_ _| / ___|| |__ ___ _ __ \n");
- win.addstr(" | ' /| __|| | \\___ \\| '_ \\ / _ \\| '_ \\ \n");
- win.addstr(" | . \\| |_ | | ___) | | | | (_) | |_) )\n");
- win.addstr(" |_|\\_\\\\__||_| |____/|_| |_|\\___/| .__/ \n");
- win.addstr(" |_| \n");
-
- win.clrtobot();
-
- win.box(0, 0);
-
- win.refresh();
- }
-
- public void redraw() {
- win.touchwin();
- win.refresh();
- }
-
-}
diff --git a/src/ui/status.vala b/src/ui/status.vala
deleted file mode 100644
index db33820..0000000
--- a/src/ui/status.vala
+++ /dev/null
@@ -1,24 +0,0 @@
-using Curses;
-
-public class StatusPanel {
- Window win;
-
- public StatusPanel() {
- win = new Window(1, COLS - 2, LINES-1, 1);
- win.bkgdset(COLOR_PAIR(2) | Attribute.BOLD);
-
- win.clrtobot();
- win.refresh();
- }
-
- public void set(string msg) {
- win.mvaddstr(0,1, msg);
- win.clrtobot();
- win.refresh();
- }
-
- public void redraw() {
- win.touchwin();
- win.refresh();
- }
-}
diff --git a/src/web/Makefile b/src/web/Makefile
new file mode 100644
index 0000000..cc9d77e
--- /dev/null
+++ b/src/web/Makefile
@@ -0,0 +1,9 @@
+all: web
+
+web: main.vala web.vala websession.vala csv.vala template.vala ../database/db-interface.vala ../pgp/pgp-interface.vala ../price.vapi
+ valac -o $@ --vapidir=../../vapi --pkg gee-1.0 --pkg gio-2.0 --pkg libsoup-2.4 --pkg posix --pkg libarchive --pkg gpgme $^
+
+clean:
+ rm -rf web
+
+.PHONY: all clean
diff --git a/src/web/csv.vala b/src/web/csv.vala
new file mode 100644
index 0000000..4e32a0a
--- /dev/null
+++ b/src/web/csv.vala
@@ -0,0 +1,75 @@
+/* Copyright 2012, Sebastian Reichel <sre@ring0.de>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+public class CSVMemberFile {
+ private UserInfo[] members;
+
+ public Gee.List<int> missing_unblocked_members() {
+ var result = new Gee.ArrayList<int>();
+ var dbusers = db.get_member_ids();
+
+ foreach(var u in dbusers) {
+ bool found=false;
+ foreach(var m in members) {
+ if(u == m.id) {
+ found=true;
+ break;
+ }
+ }
+
+ if(!found) {
+ if(!db.user_is_disabled(u))
+ result.add(u);
+ }
+ }
+
+ return result;
+ }
+
+ private string[] csv_split(string line) {
+ return /;(?=(?:[^\"]*\"[^\"]*\")*(?![^\"]*\"))/.split(line);
+ }
+
+ private string csv_value(string value) {
+ if(value[0] == '"' && value[value.length-1] == '"')
+ return value.substring(1,value.length-2);
+ else
+ return value;
+ }
+
+ public CSVMemberFile(string data) {
+ foreach(var line in data.split("\n")) {
+ var linedata = csv_split(line);
+ if(linedata.length >= 9) {
+ var m = UserInfo();
+ m.id = int.parse(csv_value(linedata[0]));
+ m.email = csv_value(linedata[1]);
+ m.firstname = csv_value(linedata[2]);
+ m.lastname = csv_value(linedata[3]);
+ m.street = csv_value(linedata[4]);
+ m.postcode = int.parse(csv_value(linedata[5]));
+ m.city = csv_value(linedata[6]);
+ m.gender = csv_value(linedata[7]) == "m" ? "masculinum" : csv_value(linedata[7]) == "w" ? "femininum" : "unknown";
+ m.pgp = csv_value(linedata[8]);
+ if(csv_value(linedata[0]) != "EXTERNEMITGLIEDSNUMMER")
+ members += m;
+ }
+ }
+ }
+
+ public UserInfo[] get_members() {
+ return members;
+ }
+}
diff --git a/src/web/main.vala b/src/web/main.vala
new file mode 100644
index 0000000..07dbb03
--- /dev/null
+++ b/src/web/main.vala
@@ -0,0 +1,35 @@
+/* Copyright 2013, Sebastian Reichel <sre@ring0.de>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+Database db;
+public CSVMemberFile csvimport;
+public PGP pgp;
+
+public static int main(string[] args) {
+ try {
+ db = Bus.get_proxy_sync(BusType.SESSION, "io.mainframe.shopsystem.Database", "/io/mainframe/shopsystem/database");
+ pgp = Bus.get_proxy_sync(BusType.SESSION, "io.mainframe.shopsystem.PGP", "/io/mainframe/shopsystem/pgp");
+ } catch(IOError e) {
+ error("IOError: %s\n", e.message);
+ }
+
+ /* attach WebServer to MainLoop */
+ new WebServer();
+
+ /* start MainLoop */
+ new MainLoop().run();
+
+ return 0;
+}
diff --git a/src/template.vala b/src/web/template.vala
index 8fe56d0..8fe56d0 100644
--- a/src/template.vala
+++ b/src/web/template.vala
diff --git a/src/web.vala b/src/web/web.vala
index 7140c22..9dfb1ae 100644
--- a/src/web.vala
+++ b/src/web/web.vala
@@ -88,7 +88,8 @@ public class WebServer {
try {
var name = db.get_username(m);
data += @"<tr><td>$m</td><td><a href=\"/users/$m\">$name</a></td></tr>";
- } catch(WebSessionError e) {
+ } catch(DatabaseError e) {
+ /* TODO: write error to log */
}
}
t.replace("DATA", data);
@@ -184,11 +185,11 @@ public class WebServer {
/* new & changed users */
string data1 = "";
foreach(var member in csvimport.get_members()) {
- if(member.exists_in_db() && !member.equals_db()) {
+ if(db.user_exists(member.id) && db.user_equals(member)) {
var dbmember = db.get_user_info(member.id);
data1 += @"<tr class=\"error\"><td><i class=\"icon-minus-sign\"></i><td>$(dbmember.id)</td><td>$(dbmember.firstname)</td><td>$(dbmember.lastname)</td><td>$(dbmember.email)</td><td>$(dbmember.gender)</td><td>$(dbmember.street)</td><td>$(dbmember.postcode)</td><td>$(dbmember.city)</td><td>$(dbmember.pgp)</td></tr>";
}
- if(!member.exists_in_db() || !member.equals_db()) {
+ if(!db.user_exists(member.id) || !db.user_equals(member)) {
data1 += @"<tr class=\"success\"><td><i class=\"icon-plus-sign\"></td><td>$(member.id)</td><td>$(member.firstname)</td><td>$(member.lastname)</td><td>$(member.email)</td><td>$(member.gender)</td><td>$(member.street)</td><td>$(member.postcode)</td><td>$(member.city)</td><td>$(member.pgp)</td></tr>";
}
}
@@ -325,8 +326,8 @@ public class WebServer {
t.menu_set_active("users");
/* years, in which something has been purchased by the user */
- var first = db.get_first_purchase(id);
- var last = db.get_last_purchase(id);
+ var first = new DateTime.from_unix_local(db.get_first_purchase(id));
+ var last = new DateTime.from_unix_local(db.get_last_purchase(id));
string years = "";
for(int i=first.get_year(); i <= last.get_year(); i++) {
years += @"<li><a href=\"/users/$id/invoice/$i/$selectedmonth/$selectedday\">$i</a></li>";
@@ -659,7 +660,7 @@ public class WebServer {
}
}
-
+#if 0
void handler_stats(Soup.Server server, Soup.Message msg, string path, GLib.HashTable? query, Soup.ClientContext client) {
try {
var l = new WebSession(server, msg, path, query, client);
@@ -749,6 +750,7 @@ public class WebServer {
handler_404(server, msg, path, query, client);
}
}
+#endif
void handler_js(Soup.Server server, Soup.Message msg, string path, GLib.HashTable? query, Soup.ClientContext client) {
try {
@@ -837,12 +839,14 @@ public class WebServer {
srv.add_handler("/products", handler_products);
srv.add_handler("/products/new", handler_products_new);
+#if 0
/* stats */
srv.add_handler("/stats", handler_stats);
srv.add_handler("/stats/stock", handler_stats_stock);
srv.add_handler("/stats/profit_per_day", handler_stats_profit_per_day);
srv.add_handler("/stats/profit_per_weekday", handler_stats_profit_per_weekday);
srv.add_handler("/stats/profit_per_product", handler_stats_profit_per_product);
+#endif
/* users */
srv.add_handler("/users", handler_users);
diff --git a/src/websession.vala b/src/web/websession.vala
index 5c562c6..5c562c6 100644
--- a/src/websession.vala
+++ b/src/web/websession.vala