diff --git a/html/attachment.svg b/html/attachment.svg
index 2c06bc2..31ff977 100644
--- a/html/attachment.svg
+++ b/html/attachment.svg
@@ -1,160 +1,56 @@
-
+
+
+ inkscape:zoom="14.3"
+ inkscape:cx="30"
+ inkscape:cy="30"
+ inkscape:window-x="-2"
+ inkscape:window-y="24"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="svg4573" />
\ No newline at end of file
diff --git a/html/chat.html b/html/chat.html
index 06874bc..0bbdb80 100644
--- a/html/chat.html
+++ b/html/chat.html
@@ -1,12 +1,40 @@
-
+
diff --git a/html/messagetable.php b/html/messagetable.php
index 2421a5d..efa6efa 100644
--- a/html/messagetable.php
+++ b/html/messagetable.php
@@ -4,7 +4,9 @@ try {
$db = new mysqli("mysql", "root", $_SERVER["MYSQL_ENV_MYSQL_ROOT_PASSWORD"]);
$db->query("create database if not exists safechat;");
$db->select_db("safechat");
- $db->query('create table if not exists message (id int primary key not null auto_increment, time timestamp default current_timestamp, user varchar(50) not null, msg text not null);');
+ $db->query('create table if not exists message (id int primary key not null auto_increment, time timestamp default current_timestamp, user varchar(50) not null, msg longtext not null);');
+ $db->query('set global max_allowed_packet=1000000000');
+ $db->query('set global net_buffer_length=1000000');
} catch (Exception $e) {
echo json_encode(null);
}
diff --git a/html/safechat.css b/html/safechat.css
index 5cb690f..b2491fd 100644
--- a/html/safechat.css
+++ b/html/safechat.css
@@ -3,6 +3,12 @@
padding: 0;
}
+@media (min-resolution: 120dpi) {
+ html {
+ font-size: 120%;
+ }
+}
+
p {
padding: .5em 0 1em 0;
}
@@ -31,6 +37,23 @@ form input#msg {
flex-grow: 4;
}
+.buttongroup {
+ flex-grow: 0;
+ display: flex;
+ flex-direction: row;
+ flex-wrap: nowrap;
+}
+.buttongroup .toolbutton {
+ flex-grow: 1;
+ text-align: center;
+}
+.toolbutton label img {
+ height: 1.5em;
+}
+.toolbutton input {
+ display:none;
+}
+
table {
width: 100%;
}
@@ -74,13 +97,16 @@ td:last-child {
}
}
#status.error {
- background-color: lightred;
+ background-color: red;
+ color: black;
}
#status.notice {
background-color: yellow;
+ color: black;
}
#status.success {
background-color: lightgreen;
+ color: black;
}
#main {
@@ -93,36 +119,58 @@ td:last-child {
#msgs .msg {
border: 1px solid black;
margin: 1ex;
- padding: 1ex;
border-radius: 2ex;
- -moz-border-radius: 1em;
- -webkit-border-radius: 1em;
+ -moz-border-radius: 2ex;
+ -webkit-border-radius: 2ex;
+ display: block;
+ width: auto;
+ height: auto;
+ max-width: 60%;
}
#msgs .me {
float: left;
+ background-color: lightgray;
}
#msgs .other {
float: right;
+ background-color: lightyellow;
}
#msgs .msg .header {
- border-bottom: 1px solid black;
+ border: 1px solid black;
+ border-radius: 2ex 2ex 0 0;
+ -moz-border-radius: 2ex 2ex 0 0;
+ -webkit-border-radius: 2ex 2ex 0 0;
+ /*border-radius: 2ex;
+ -moz-border-radius: 2ex;
+ -webkit-border-radius: 2ex;*/
margin-bottom: .25ex;
padding-bottom: .25ex;
position: relative;
height: 1em;
+ padding: .5ex 1ex .5ex 1ex;
+}
+#msgs .msg .header {
+ background-color: lightgreen;
}
#msgs .msg .header .date {
font-size: xx-small;
float: left;
- /*position: absolute;
- left: 0;*/
+ padding: 0 1ex 0 0;
}
#msgs .msg .header .sender {
font-size: small;
float: right;
- /*position: absolute;
- right: 0;*/
+ padding: 0 0 0 1ex;
}
#msgs .msg .text {
float: left;
+ padding: .5ex 1ex .5ex 1ex;
+}
+#msgs .msg img {
+ display: block;
+ width: 99%;
+}
+
+#preview img {
+ height: 4em;
}
diff --git a/html/safechat.js b/html/safechat.js
index 3a46a6e..3d8e77d 100644
--- a/html/safechat.js
+++ b/html/safechat.js
@@ -1,5 +1,6 @@
-var password = null;
-var username = null;
+var password = null; // password, only stored temporary, until reload
+var username = null; // username, only used during registration
+var filecontent = new Array(); // temporary storage for attachments
function error(data, stay) {
$("#status").fadeOut("slow", function() {
@@ -11,7 +12,7 @@ function error(data, stay) {
$("#status").html(data);
console.log("error: "+data);
} else {
- $("#status").html(''+JSON.stringify(data)+'
');
+ $("#status").html('error');
console.log("error: "+JSON.stringify(data));
}
} else {
@@ -151,18 +152,46 @@ function userid() {
return publicKey().keys[0].getUserIds()[0];
}
+function clearmessage() {
+ filecontent = new Array();
+ $('#preview').empty();
+ $("#msg").val("");
+ notice("message cleared");
+}
+
+function attachments(files, id) {
+ if (files) files.forEach(function(file) {
+ //if (file.content.length<1000000) {
+ var img = document.createElement('img');
+ img.src = 'data:'+file.type+';base64,' + file.content;
+ $(id).append(img);
+ //}
+ });
+}
+
function fileupload(evt) {
if (!window.FileReader)
return error("your browser dows not support file upload", true);
- var reader = new FileReader();
- reader.onload = function(evt) {
- if (evt.target.readyState!=2)
- return notice("ReadyState="+evt.target.readyState);
- if (evt.target.error) return error("error reading file", true);
- filecontent = evt.target.result;
- success(filecontent);
+ for (var i=0, f; f=evt.target.files[i]; ++i) {
+ var file = f;
+ var reader = new FileReader();
+ reader.onload = function(evt) {
+ if (evt.target.error) return error("error reading file", true);
+ if (evt.target.readyState==0) return notice("waiting for data ...");
+ if (evt.target.readyState==1) return notice("loading data ...");
+ var base64 = btoa(evt.target.result);
+ filecontent.push({type: file.type, content: base64});
+ if (file.type.match('^image/')) {
+ var img = document.createElement('img');
+ img.src = 'data:'+file.type+';base64,' + base64;
+ $("#preview").append(img);
+ success('image of type '+file.type+' is ready to be sent');
+ } else {
+ success('file of type '+file.type+' is ready to be sent');
+ }
+ }
+ reader.readAsBinaryString(file);
}
- reader.readAsText(evt.target.files[0]);
}
function setreceiver(name) {
@@ -171,83 +200,101 @@ function setreceiver(name) {
$("#msg").focus();
}
-var startmsg = 0;
+var startmsg = 0; // number of last downloaded message
function get() {
var beeped = false;
$.post("get.php", {start: startmsg}).done(function(res) {
var msgs = JSON.parse(res);
if (msgs) {
msgs.forEach(function(e) {
- if (startmsg'+
- msg.text+
- '
');
- $('#id'+(e["id"])).emoticonize();
- if (!beeped)
- (new Audio("A-Tone-His_Self-1266414414.mp3"))
- .play();
- beeped = true;
- });
-// .catch(function(e) {
-// error("decryption of message failed", true);
-// });
+ setTimeout(get, 10000);
+ return error("key of receiver not found", true);
}
+ var message = openpgp.message.readArmored(e.msg);
+ var privkey = privateKey().keys[0];
+ if (privkey.decrypt(password))
+ openpgp.decryptAndVerifyMessage(privkey, key.keys, message)
+ .then(function(msg) {
+ var message = JSON.parse(msg.text);
+ $("#msgs") // todo: check msg.signatures[0].valid
+ .prepend(''+
+ '
'+
+ message.text+
+ '
');
+ attachments(message.files, '#id'+e.id+' .text');
+ $('#id'+e.id).emoticonize();
+ if (!beeped)
+ (new Audio("A-Tone-His_Self-1266414414.mp3"))
+ .play();
+ beeped = true;
+ })
+ .catch(function(e) {
+ // not for me
+ });
}).fail(function(e) {
error("get sender's key from server failed", true);
});
});
}
- setTimeout(get, 10000);
- }).fail(error);
+ }).fail(function(e) {
+ error("get messages failed")
+ });
+ setTimeout(get, 10000);
}
function sendmessage(recv, txt) {
+ notice("1/3 preparing message ...");
+ $("#message").fadeOut("slow");
$.post("pubkey.php", {user: recv}).done(function(pk) {
var res=JSON.parse(pk);
var key=openpgp.key.readArmored(res);
if (!res||key.err) {
+ $("#message").fadeIn("slow");
error("key of receiver not found", true);
return;
}
var privkey = privateKey().keys[0];
privkey.decrypt(password);
- openpgp.signAndEncryptMessage(key.keys.concat(publicKey().keys), privkey, txt)
+ var message = JSON.stringify({text: txt, files: filecontent});
+ notice("2/3 encrypting message ...");
+ openpgp.signAndEncryptMessage(key.keys.concat(publicKey().keys), privkey, message)
.then(function(msg) {
+ notice("3/3 sending message ...");
$.post("send.php", {user: userid(), msg: msg})
.done(function(res) {
if (JSON.parse(res)) {
- $("#msg").val("");
+ $("#message").fadeIn("slow");
+ clearmessage();
success("message sent");
- } else error("error sending message", true);
+ } else {
+ $("#message").fadeIn("slow");
+ error("error sending message", true);
+ }
})
.fail(error);
})
.catch(function(e) {
+ $("#message").fadeIn("slow");
error("encryption of message failed", true);
});
}).fail(function(e) {
+ $("#message").fadeIn("slow");
error("get receiver's key from server failed", true);
});
+ $("#message").fadeIn("slow");
}
function setpw(pwd) {
diff --git a/html/send.php b/html/send.php
index 365b4d8..84aca1f 100644
--- a/html/send.php
+++ b/html/send.php
@@ -4,7 +4,12 @@ try {
$user = $db->real_escape_string($_REQUEST['user']);
$msg = $db->real_escape_string($_REQUEST['msg']);
$q = $db->query("insert into message (user, msg) values ('$user', '$msg');");
- echo json_encode(true);
+ if ($q) {
+ echo json_encode(true);
+ } else {
+ error_log("Error storing message: ".$db->error);
+ echo json_encode(false);
+ }
} catch (Exception $e) {
echo json_encode(false);
}