From 2bc485023a0ab6e3eb5de2314ab6bae680f29280 Mon Sep 17 00:00:00 2001
From: dadav <33197631+dadav@users.noreply.github.com>
Date: Mon, 30 Sep 2019 11:21:15 +0200
Subject: [PATCH 1/4] Add pwnagotchi preview

---
 scripts/language.sh |   1 +
 scripts/preview.py  | 157 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 158 insertions(+)
 create mode 100755 scripts/preview.py

diff --git a/scripts/language.sh b/scripts/language.sh
index c56b784..cf653f5 100755
--- a/scripts/language.sh
+++ b/scripts/language.sh
@@ -55,6 +55,7 @@ function update_lang() {
   msgmerge --update "$LOCALE_DIR/$1/LC_MESSAGES/voice.po" "$LOCALE_DIR/voice.pot"
 }
 
+
 case "$1" in
   add)
     add_lang "$2"
diff --git a/scripts/preview.py b/scripts/preview.py
new file mode 100755
index 0000000..47afd7d
--- /dev/null
+++ b/scripts/preview.py
@@ -0,0 +1,157 @@
+#!/usr/bin/env python3
+
+import sys
+import os
+import time
+import argparse
+import random
+from http.server import HTTPServer
+import shutil
+import yaml
+sys.path.insert(0,
+                os.path.join(os.path.dirname(os.path.realpath(__file__)),
+                             '../sdcard/rootfs/root/pwnagotchi/scripts/'))
+
+from pwnagotchi.ui.view import View
+from pwnagotchi.ui.display import Display, VideoHandler
+import core
+
+class CustomDisplay(Display):
+
+    def _http_serve(self):
+        if self._video_address is not None:
+            self._httpd = HTTPServer((self._video_address, self._video_port),
+                                    CustomVideoHandler)
+            core.log("ui available at http://%s:%d/" % (self._video_address,
+                                                        self._video_port))
+            self._httpd.serve_forever()
+        else:
+            core.log("could not get ip of usb0, video server not starting")
+
+
+    def _on_view_rendered(self, img):
+        CustomVideoHandler.render(img)
+
+        if self._enabled:
+            self.canvas = (img if self._rotation == 0 else img.rotate(self._rotation))
+            if self._render_cb is not None:
+                self._render_cb()
+
+
+class CustomVideoHandler(VideoHandler):
+
+    @staticmethod
+    def render(img):
+        with CustomVideoHandler._lock:
+            img.save("/tmp/pwnagotchi-{rand}.png".format(rand=id(CustomVideoHandler)), format='PNG')
+
+    def do_GET(self):
+        if self.path == '/':
+            self.send_response(200)
+            self.send_header('Content-type', 'text/html')
+            self.end_headers()
+            try:
+                self.wfile.write(
+                    bytes(
+                        self._index %
+                        ('localhost', 1000), "utf8"))
+            except BaseException:
+                pass
+
+        elif self.path.startswith('/ui'):
+            with self._lock:
+                self.send_response(200)
+                self.send_header('Content-type', 'image/png')
+                self.end_headers()
+                try:
+                    with open("/tmp/pwnagotchi-{rand}.png".format(rand=id(CustomVideoHandler)), 'rb') as fp:
+                        shutil.copyfileobj(fp, self.wfile)
+                except BaseException:
+                    pass
+        else:
+            self.send_response(404)
+
+
+class DummyPeer:
+    @staticmethod
+    def name():
+        return "beta"
+
+
+def main():
+    parser = argparse.ArgumentParser(description="This program emulates\
+                                     the pwnagotchi display")
+    parser.add_argument('--display', help="Which display to use.",
+                        default="waveshare_2")
+    parser.add_argument('--port', help="Which port to use",
+                        default=8080)
+    parser.add_argument('--sleep', type=int, help="Time between emotions",
+                        default=2)
+    parser.add_argument('--lang', help="Language to use",
+                        default="en")
+    args = parser.parse_args()
+
+    CONFIG = yaml.load('''
+    main:
+        lang: {lang}
+    ui:
+        fps: 0.3
+        display:
+            enabled: false
+            rotation: 180
+            color: black
+            refresh: 30
+            type: {display}
+            video:
+                enabled: true
+                address: "127.0.0.1"
+                port: {port}
+    '''.format(display=args.display,
+               port=args.port,
+               lang=args.lang),
+                       Loader=yaml.FullLoader)
+
+    DISPLAY = CustomDisplay(config=CONFIG, state={'name': '%s>' % 'preview'})
+
+    while True:
+        DISPLAY.on_starting()
+        DISPLAY.update()
+        time.sleep(args.sleep)
+        DISPLAY.on_ai_ready()
+        DISPLAY.update()
+        time.sleep(args.sleep)
+        DISPLAY.on_normal()
+        DISPLAY.update()
+        time.sleep(args.sleep)
+        DISPLAY.on_new_peer(DummyPeer())
+        DISPLAY.update()
+        time.sleep(args.sleep)
+        DISPLAY.on_lost_peer(DummyPeer())
+        DISPLAY.update()
+        time.sleep(args.sleep)
+        DISPLAY.on_free_channel('6')
+        DISPLAY.update()
+        time.sleep(args.sleep)
+        DISPLAY.wait(args.sleep)
+        DISPLAY.update()
+        DISPLAY.on_bored()
+        DISPLAY.update()
+        time.sleep(args.sleep)
+        DISPLAY.on_sad()
+        DISPLAY.update()
+        time.sleep(args.sleep)
+        DISPLAY.on_motivated(1)
+        DISPLAY.update()
+        time.sleep(args.sleep)
+        DISPLAY.on_demotivated(-1)
+        DISPLAY.update()
+        time.sleep(args.sleep)
+        DISPLAY.on_excited()
+        DISPLAY.update()
+        time.sleep(args.sleep)
+        DISPLAY.on_deauth({'mac': 'DE:AD:BE:EF:CA:FE'})
+        DISPLAY.update()
+
+
+if __name__ == '__main__':
+    SystemExit(main())

From c9996e358e88185c27a11d4b1c072a962b2f4be9 Mon Sep 17 00:00:00 2001
From: dadav <33197631+dadav@users.noreply.github.com>
Date: Tue, 1 Oct 2019 12:28:34 +0200
Subject: [PATCH 2/4] Update Readme

---
 README.md | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/README.md b/README.md
index 66eba58..2179f69 100644
--- a/README.md
+++ b/README.md
@@ -78,7 +78,7 @@ usage: ./scripts/create_sibling.sh [OPTIONS]
 
 #### Host Connection Share
 
-If you connect to the unit via `usb0` (thus using the data port), you might want to use the `scripts/(linux|macos)_connection_share.sh` script to bring the interface up on your end and share internet connectivity from another interface, so you can update the unit and generally download things from the internet on it.
+If you connect to the unit via `usb0` (thus using the data port), you might want to use the `scripts/linux_connection_share.sh` script to bring the interface up on your end and share internet connectivity from another interface, so you can update the unit and generally download things from the internet on it.
 
 ### UI
 
@@ -98,7 +98,6 @@ Pwnagotchi is able to speak multiple languages!! Currently supported are:
 
 * **english** (default)
 * german
-* dutch
 
 If you want to add a language use the `language.sh` script.
 If you want to add for example the language **italian** you would type:
@@ -121,6 +120,14 @@ If you changed the `voice.py`- File, the translations need an update. Do it like
 # DONE
 ```
 
+Now you can use the `preview.py`-script to preview the changes:
+
+```shell
+./scripts/preview.py --lang it --display ws2 --port 8080 &
+./scripts/preview.py --lang it --display inky --port 8081 &
+# Now open http://localhost:8080 and http://localhost:8081
+```
+
 ### Random Info
 
 - `hostname` sets the unit name.

From 19c4b420724ce639987764bdacf4f8bdfc024a7f Mon Sep 17 00:00:00 2001
From: Panagiotis Vasilopoulos <hello@alwayslivid.com>
Date: Tue, 1 Oct 2019 16:26:14 +0000
Subject: [PATCH 3/4] Improved Greek translation files

---
 .../pwnagotchi/locale/gr/LC_MESSAGES/voice.mo | Bin 4750 -> 4763 bytes
 .../pwnagotchi/locale/gr/LC_MESSAGES/voice.po |  74 +++++++++---------
 2 files changed, 36 insertions(+), 38 deletions(-)

diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale/gr/LC_MESSAGES/voice.mo b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale/gr/LC_MESSAGES/voice.mo
index 434c3b8426a1ea2236573ce376eefaf58166c189..b2bf23d5864ca468cb0e46eddcc9738a6b8c708c 100644
GIT binary patch
delta 1050
zcmYk)+e_177zglo2GV|;TZ#~Nd{?dm>fDw^&0OF`Q4x7j5OfivCJH)B6r(YAQm0^o
z{V0P@QeJM_m{aDazpLn`p7*xHKM-}(O&38_-)EbVHy@w(@EqRXW}Q!*uV+lr8zv#t
zb|D&s5bc@}2Vpn73VY!`Sb_)OXXt>xVK<Z(A==<gI0)yUAO3;O&~FuDKkvgvn1qMm
zW4H?%RuL`#^9c*PvG4;Pf%SDL0)6ljJY^GN4@^OBWD!dEwi<tdM-f}>LNvkSkQ==W
zcfdRF0!+Xb_#S%UPkXd7Nh?lW#KI8dLPf|g@d0+hU+@g{)mQfK!4Aapkk7q?T<|+Q
z1{?649G`_eX&>APlh6eDkMB8i=54lGo5$Ve_DIhOpV!;scI!^_gPP!gUNT=ld9CeS
zFccgPj0_F?WY19WR{x0fy1XurCTNkKNy?~kGN?c$T5}0{r6y>DRw$!)YF9c`it<!Y
zamuPGTBf{8gl`Xw4hIGz4nYfu$0@C*k%Kk?qBYvk-)N_sRE&z0MW!WQ#9^HiQCjK_
zi{I?f!ef1bkw~lFYx&rW$_7qmRZ7jMgyc|7NSDhcdd5P?A6L^jXze;5<AAaf$qg#1
z`{gs`HsZL?ji6Wtg}GD~MIZfZO46#Drlo3f{hM`f&RTcZ)c6#+xXp5vtpQ%zT5IRf
ziHhmU)~Q?U{^%s8FOtD?Y^YguQBX;A5)O?HMx?6lstJ|gM>Y6SQy2(G(8WAAoaZ}O
zj#IAEo&?K0HWf6qjXNbZgP1Sl%sR@g;VIJPmYb>%LeFt)o!<wE(zHrO?yJ4MCfeVL
zIxnyqL)&;csnJ8)L<f`Q>6TTJKLc*&c}7DEhXRAa2tM}$=Q^yC68U(KLFG*K10gGq
ZQ#r1o{Ym^hFhJ$yr?!T){h!q#{sPLek?a5f

delta 1027
zcmZXRT}YEr7{{OWWqaL+MuAb;Yqd<QvBVTJ7X(2c23^#ZbTMjV_<?9*WwLaeCTL&>
zZ!Ab82x8OLoa=S7-9%UQoSPuJi=vAzqN}cg=>NQ16g1d==RBYP^WOvCJ>Rn_N92@)
zNN*<ELPS*tQ5{$hwu2W-_XThd?r*>v@H==KtSm<@*a7x{6JQYh0UiJwT}0L3C2%Wv
z8*Bh)z+K=g7exrO=o13F!Ec~6y4^&-z$Wk<c*H}rAB=(`<SDoVd<*Uczk(v%?JeG$
zL0cGz5i|jw0cT73kDv(IP!S<IfkSfz(OK{oxD$L0%HYpn8(3CJbR0YhN<I!Yf(xM3
zy$40uPf#9G4LkRNL2w&*859R@f-v0vNS`n5T<_WB3A7w)XfY2r9t{NQ0}aaOyua~k
ze>mKwEN6%E8&xhH)f1f2F<#;o)oxs9>J0T>8R!gkg@^mP2m3?aBQ?Y``VJTHwNM?i
zPX*Lxb(FIv0$Dw#-WkVCp648=c#Rh&h(5&`wm4y;u%P3Hsw)qc8N)-Jq3a{6ulz%;
zj73Y17fsINxQ6bRn4B{Gem|Wb>g9wU)sw2n)pjk8;*1{U=XQ(5t1{Q_*VA@6-<6lJ
z^*4%ijuWU%LCa$<n7pDVah%19JXTpI=d{et;+n+vf(%MmxNkVB=a8DzF;UKW*`udX
zfZ^gmRz36_bj&OEv^oZq(;M_gbsXsgFGE32kE?d?_DC_7LM$mUu|SUzKS9|GtX$>H
zA6a=lWp5V~blgOJ8tI&^D`jBh64JI__+7NY;v~#S+Xffy;yFmQFd|WWT>6W*ZrvbT
zt=RHNo~g&=dB$*Ws3$yPpnn{qF~LtfFMDh8*o=v(_=yRiAX!`bziQ~eKHK$D6xRRq
Fs^8G~jJp5;

diff --git a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale/gr/LC_MESSAGES/voice.po b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale/gr/LC_MESSAGES/voice.po
index 2d21d99..26a2511 100644
--- a/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale/gr/LC_MESSAGES/voice.po
+++ b/sdcard/rootfs/root/pwnagotchi/scripts/pwnagotchi/locale/gr/LC_MESSAGES/voice.po
@@ -1,18 +1,17 @@
 # pwnigotchi voice data
 # Copyright (C) 2019
 # This file is distributed under the same license as the pwnagotchi package.
-# FIRST AUTHOR <33197631+dadav@users.noreply.github.com>, 2019.
+# FIRST AUTHOR Perilis Fregkos <fregkos@gmail.com>, 2019.
 #
-#, fuzzy
 msgid ""
 msgstr ""
 "Project-Id-Version: 0.0.1\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2019-09-29 13:42+0200\n"
-"PO-Revision-Date: 2019-09-29 14:00+0200\n"
-"Last-Translator: dadav <33197631+dadav@users.noreply.github.com>\n"
+"PO-Revision-Date: 2019-10-01 16:22+0000\n"
+"Last-Translator: Panos Vasilopoulos <hello@alwayslivid.com>\n"
 "Language-Team: pwnagotchi <33197631+dadav@users.noreply.github.com>\n"
-"Language: greek\n"
+"Language: el\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=utf-8\n"
 "Content-Transfer-Encoding: 8bit\n"
@@ -39,7 +38,7 @@ msgstr ""
 
 #: voice.py:23
 msgid "Hack the Planet!"
-msgstr "Hackαρε τον Πλανήτη!"
+msgstr "Hackαρε τον πλανήτη!"
 
 #: voice.py:28
 msgid "AI ready."
@@ -70,7 +69,7 @@ msgstr "Βαριέμαι ..."
 
 #: voice.py:45
 msgid "Let's go for a walk!"
-msgstr "Πάμε μια βόλτα!"
+msgstr "Ας πάμε μια βόλτα!"
 
 #: voice.py:49
 msgid ""
@@ -86,7 +85,7 @@ msgstr "Σκατένια μέρα :/"
 
 #: voice.py:58
 msgid "I'm extremely bored ..."
-msgstr "Βαριέμαι υπερβολικά πολύ ..."
+msgstr "Βαριέμαι πάρα πολύ ..."
 
 #: voice.py:59
 msgid "I'm very sad ..."
@@ -94,15 +93,15 @@ msgstr "Είμαι πολύ λυπημένο ..."
 
 #: voice.py:60
 msgid "I'm sad"
-msgstr "Είμαι λυπημένο ..."
+msgstr "Είμαι λυπημένο"
 
 #: voice.py:66
 msgid "I'm living the life!"
-msgstr "Το ζω!"
+msgstr "Ζω την ζωή μου!"
 
 #: voice.py:67
 msgid "I pwn therefore I am."
-msgstr "Pwnάρω άρα υπάρχω."
+msgstr "Pwnάρω, άρα υπάρχω."
 
 #: voice.py:68
 msgid "So many networks!!!"
@@ -112,15 +111,15 @@ msgstr "Τόσα πολλά δίκτυα!!!"
 msgid ""
 "I'm having so much\n"
 "fun!"
-msgstr "Έχει πολύ πλάκα!"
+msgstr "Περνάω τέλεια!"
 
 #: voice.py:70
 msgid ""
 "My crime is that of\n"
 "curiosity ..."
 msgstr ""
-"Το μόνο μου έγκλημα\n"
-"είναι η περιέργεια ..."
+"Η περιέργεια είναι\n"
+"το μόνο έγκλημά μου ..."
 
 #: voice.py:75
 #, python-brace-format
@@ -129,8 +128,7 @@ msgid ""
 "{name}!\n"
 "Nice to meet you. {name}"
 msgstr ""
-"Γειά σου\n"
-"{name}!\n"
+"Γειά {name}!\n"
 "Χάρηκα για τη γνωριμία. {name}"
 
 #: voice.py:76
@@ -161,7 +159,7 @@ msgid ""
 "{name}\n"
 "is gone ..."
 msgstr ""
-"{name}\n"
+"Το {name}\n"
 "έφυγε ..."
 
 #: voice.py:87
@@ -171,9 +169,9 @@ msgid ""
 "{name}\n"
 "is gone."
 msgstr ""
-"Ουπς ...\n"
-"{name}\n"
-"έφυγε."
+"Ουπς ... \n"
+"Εξαφανίστηκε το\n"
+"{name}."
 
 #: voice.py:88
 #, python-brace-format
@@ -181,12 +179,12 @@ msgid ""
 "{name}\n"
 "missed!"
 msgstr ""
-"{name}\n"
-"χάθηκε!"
+"Έχασα το\n"
+"{name}!"
 
 #: voice.py:89
 msgid "Missed!"
-msgstr "Χάθηκε!"
+msgstr "Το έχασα!"
 
 #: voice.py:94
 msgid ""
@@ -198,16 +196,16 @@ msgstr ""
 
 #: voice.py:95
 msgid "I feel so alone ..."
-msgstr "Νιώθω πολλή μοναξία ..."
+msgstr "Νιώθω μοναχός μου ..."
 
 #: voice.py:96
 msgid "Where's everybody?!"
-msgstr "Μα, πού πήγαν όλοι;!"
+msgstr "Μα, πού πήγαν όλοi;!"
 
 #: voice.py:101
 #, python-brace-format
 msgid "Napping for {secs}s ..."
-msgstr "Κοιμάμαι για {secs}s ..."
+msgstr "Ξεκουράζομαι για {secs}s ..."
 
 #: voice.py:102
 msgid "Zzzzz"
@@ -226,7 +224,7 @@ msgstr "Περιμένω για {secs}s ..."
 #: voice.py:114
 #, python-brace-format
 msgid "Looking around ({secs}s)"
-msgstr "Ψάχνω τριγύρω ({secs}s)"
+msgstr "Ψάχνω τριγύρω ({secs})"
 
 #: voice.py:121
 #, python-brace-format
@@ -235,8 +233,8 @@ msgid ""
 "{what}\n"
 "let's be friends!"
 msgstr ""
-"Εε\n"
-"{what}\n"
+"Εε!\n"
+"{what},\n"
 "ας γίνουμε φίλοι!"
 
 #: voice.py:122
@@ -245,7 +243,7 @@ msgid ""
 "Associating to\n"
 "{what}"
 msgstr ""
-"Συσχετίζομαι με το\n"
+"Συνδέομαι με το\n"
 "{what}"
 
 #: voice.py:123
@@ -254,7 +252,7 @@ msgid ""
 "Yo\n"
 "{what}!"
 msgstr ""
-"Που'σε ρε τρελέ'\n"
+"Που'σ ρε τρελέ\n"
 "{what}!"
 
 #: voice.py:128
@@ -274,7 +272,7 @@ msgid ""
 "Deauthenticating\n"
 "{mac}"
 msgstr ""
-"Αποπιστοποίηση της\n"
+"Πετάω έξω την\n"
 "{mac}"
 
 #: voice.py:130
@@ -283,7 +281,7 @@ msgid ""
 "Kickbanning\n"
 "{mac}!"
 msgstr ""
-"Κλωτσομπούνι στη\n"
+"Μπανάρω την\n"
 "{mac}!"
 
 #: voice.py:135
@@ -293,7 +291,7 @@ msgid ""
 "new handshake{plural}!"
 msgstr ""
 "Τέλεια δικέ μου, πήραμε {num}\n"
-"νέες handshake{plural}!"
+"νέες χειραψίες{plural}!"
 
 #: voice.py:139
 msgid ""
@@ -322,19 +320,19 @@ msgstr "Πήρα {num} χειραψίες\n"
 
 #: voice.py:147
 msgid "Met 1 peer"
-msgstr "Γνώρισα 1 συνάδελφο"
+msgstr "Γνώρισα 1 φίλο"
 
 #: voice.py:149
 #, python-brace-format
 msgid "Met {num} peers"
-msgstr "Γνώρισα {num} συναδέλφους"
+msgstr "Γνώρισα {num} φίλους"
 
 #: voice.py:154
 #, python-brace-format
 msgid ""
 "I've been pwning for {duration} and kicked {deauthed} clients! I've also met "
-"{associated} new friends and ate {handshakes} handshakes! #pwnagotchi "
-"#pwnlog #pwnlife #hacktheplanet #skynet"
+"{associated} new friends and ate {handshakes} handshakes! #pwnagotchi #pwnlog "
+"#pwnlife #hacktheplanet #skynet"
 msgstr ""
 "Pwnαρα για {duration} και έριξα {deauthed} πελάτες! Επίσης γνώρισα "
 "{associated} νέους φίλους και καταβρόχθισα {handshakes} χειραψίες! #pwnagotchi "

From 33f9917b903f0263ef81803f090b225ce3a57872 Mon Sep 17 00:00:00 2001
From: Panagiotis Vasilopoulos <hello@alwayslivid.com>
Date: Tue, 1 Oct 2019 16:41:43 +0000
Subject: [PATCH 4/4] Exception handlers in preview script

---
 scripts/preview.py | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/scripts/preview.py b/scripts/preview.py
index 47afd7d..16e4079 100755
--- a/scripts/preview.py
+++ b/scripts/preview.py
@@ -43,7 +43,10 @@ class CustomVideoHandler(VideoHandler):
     @staticmethod
     def render(img):
         with CustomVideoHandler._lock:
-            img.save("/tmp/pwnagotchi-{rand}.png".format(rand=id(CustomVideoHandler)), format='PNG')
+            try:
+              img.save("/tmp/pwnagotchi-{rand}.png".format(rand=id(CustomVideoHandler)), format='PNG')
+            except BaseException:
+              core.log("could not write preview")
 
     def do_GET(self):
         if self.path == '/':
@@ -67,7 +70,7 @@ class CustomVideoHandler(VideoHandler):
                     with open("/tmp/pwnagotchi-{rand}.png".format(rand=id(CustomVideoHandler)), 'rb') as fp:
                         shutil.copyfileobj(fp, self.wfile)
                 except BaseException:
-                    pass
+                    core.log("could not open preview")
         else:
             self.send_response(404)