[mw-devel] [Git][arthur/mw][master] 6 commits: unreturnables magical updated webclient

Andrew Price welshbyte at sucs.org
Thu Jul 20 10:56:03 BST 2017


Andrew Price pushed to branch master at Justin Mitchell / mw


Commits:
cac2a1a4 by Isabel Jenkins at 2017-07-12T14:14:05+01:00
unreturnables magical updated webclient

- - - - -
bf9e06b8 by Isabel Jenkins at 2017-07-12T14:16:39+01:00
Merge projects.sucs.org:arthur/mw

- - - - -
27157e69 by Isabel Jenkins at 2017-07-12T14:32:43+01:00
removed vendor dir

- - - - -
587273ed by Isabel Jenkins at 2017-07-18T11:47:06+01:00
Seperated out the php and webclient into two projects

- - - - -
1a090f8f by Isabel Jenkins at 2017-07-18T11:54:33+01:00
removed some late night coding 'features'

- - - - -
02fc046a by Andrew Price at 2017-07-20T10:54:54+01:00
Merge projects.sucs.org:unreturnable/mw

- - - - -


14 changed files:

- + webclient/.htaccess
- webclient/config.php
- webclient/index.php
- − webclient/jquery.js
- − webclient/mw.css
- − webclient/person.png
- webclient/poll.php
- − webclient/say.js
- webclient/send.php
- webclient/startup.php
- − webclient/templates/createaccount.html
- − webclient/templates/front.html
- − webclient/templates/login.html
- − webclient/templates/main.html


Changes:

=====================================
webclient/.htaccess
=====================================
--- /dev/null
+++ b/webclient/.htaccess
@@ -0,0 +1 @@
+Header set Access-Control-Allow-Origin "*"


=====================================
webclient/config.php
=====================================
--- a/webclient/config.php
+++ b/webclient/config.php
@@ -1,6 +1,7 @@
 <?php
 
-$poller_bin = "/usr/lib/mw/mwpoll";
+//$poller_bin = "/usr/lib/mw/mwpoll";
+$poller_bin = "/usr/local/lib/mw/mwpoll.test";
 $poller_path = "/var/run/mw/mwpoll.";
 
 /* Fix these paths to your local test copy for test mode  e.g. */


=====================================
webclient/index.php
=====================================
--- a/webclient/index.php
+++ b/webclient/index.php
@@ -1,42 +1,32 @@
 <?
-# Force the user to use HTTPS
-if (empty($_SERVER['HTTPS'])) header("Location: https://".$_SERVER['SERVER_NAME'].$_SERVER['REQUEST_URI']);
+header('Access-Control-Allow-Headers: Access-Control-Allow-Headers, Origin,Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers');
 
-define('SMARTY_DIR', '/usr/share/php/smarty/libs/');
-require("/usr/share/php/smarty/libs/Smarty.class.php");
+// Force the user to use HTTPS
+if (empty($_SERVER['HTTPS'])) header("Location: https://".$_SERVER['SERVER_NAME'].$_SERVER['REQUEST_URI']);
 
-$smarty = new Smarty;
-$smarty->assign("self", basename($_SERVER['PHP_SELF']));
+$_REQUEST = json_decode(file_get_contents('php://input'), true);
 
+// Get the users MW session if it exists
 $mwsess = @$_COOKIE['mwsess'];
-$action = @$_REQUEST['action'];
-
-if (isset($_GET['mwsess'])) {
-	$mwsess = $_GET['mwsess'];
-	setcookie("mwsess", $mwsess);
-}
+// Get the action HTTP request variable
+$action = $_REQUEST['action'];
 
-if ($action == "logout") {
-	setcookie("mwsess", "");
-	unset($mwsess);
-}
+// Check to see if login actions need to be performed
 if ($action == "login" || $action == "create") {
-require("startup.php");
+  require("startup.php");
 }
 
+// Check if the user has a MW session
 if (!isset($mwsess)) {
-	if (@$_REQUEST['sucssite_loggedin']=="true" && $action!="logout") {
-		require("startup.php");
-	} else {
-		$smarty->assign("body", $smarty->fetch("login.html"));
-		$smarty->display("main.html");
-		exit;
-	}
+
+  // If there is no session but the user is logged in then run startup
+  if ($_REQUEST['sucssite_loggedin']=="true" && $action!="logout") {
+    require("startup.php");
+  } else {
+    echo 'Post requests only to this url';
+    exit;
+  }
 }
 
 $session = unserialize($mwsess);
-
-$smarty->assign("body", $smarty->fetch("front.html"));
-$smarty->display("main.html");
-
 ?>


=====================================
webclient/jquery.js deleted
=====================================
The diff for this file was not included because it is too large.

=====================================
webclient/mw.css deleted
=====================================
--- a/webclient/mw.css
+++ /dev/null
@@ -1,432 +0,0 @@
-*:focus {
-	outline: none;
-}
-
-html, body {
-	height: 100%;
-}
-
-html, body, form, textarea {
-	margin: 0;
-	padding: 0;
-}
-
-img {
-	border: 0;
-}
-
-table#layout {
-	width: 100%;
-	height: 100%;
-	padding: 5px;
-}
-
-table#layout td {
-	vertical-align: top;
-}
-
-td#whotd {
-	width: 11em;
-	padding-left: 5px;
-}
-
-tr#inputtr {
-	height: 4em;
-}
-
-td#saytd {
-	padding-top: 5px;
-}
-
-td#buttontd {
-	padding-left: 5px;
-}
-.whoinfo {
-	padding: 5px;
-	background: #fff;
-	border: 1px solid black;
-	width: 200px;
-	position: relative;
-	top: -1.4em;
-	left: -217px;
-	z-index: 1000;
-	display: none;
-	color: black;
-}
-
-
-.whoinfo img {
-	float: right;
-	margin-left: 0.5em;
-}
-
-.whoinfo br {
-	clear: right;
-}
-
-.who a {
-	display: block;
-	width: 100%;
-	height: 100%;
-	color: inherit;
-	text-decoration: none;
-	background: inherit;
-}
-
-.who a:hover .whoinfo {
-	display: block;
-}
-textarea {
-	margin: 0;
-}
-p {
-	margin: 0;
-}
-
-table#layout, #textlist, #sayouter, #sayit, #textlist table, #wholist, #milliways, #logoutform {
-	font-family: Monaco, "Lucida Sans Typewriter", "Lucida Console", monospace;
-	font-size: 9pt;
-}
-
-#wholist {
-	position: absolute;
-	top: 5px;
-	right: 5px;
-	bottom: 5em;
-	background-color: #000000;
-	color: #d6d6d6;
-	width: 11em;
-	list-style: none;
-	margin: 0;
-	padding: 0;
-/* overflow: auto; */
-}
-
-#wholist li {
-	padding-left: 5px;
-	padding-right: 5px;
-	height: 1.3em;
-}
-
-#textlist, #sayit {
-	overflow: auto;
-	white-space: pre-wrap;
-}
-
-#textlist {
-	position: absolute;
-	top: 5px;
-	left: 5px;
-	right: 12em;
-	bottom: 5em;
-	padding: 5px;
-}
-
-#textlist table {
-	margin: 0;
-	padding: 0;
-}
-
-th {
-	text-align: left;
-}
-
-div#sayouter {
-	position: absolute;
-	bottom: 5px;
-	left: 5px;
-	right: 12em;
-margin: 0;
-padding: 5px;
-	border: 1px solid black;
-}
-textarea#sayit {
-	width: 100%;
-	height: 3em;
-	border: none;
-	resize: none;
-	padding: 0;
-}
-
-.login {
-	font-family: Arial, sans-serif;
-}
-
-h1.login {
-	text-align: center;
-	margin: 0;
-	padding: 0;
-	padding-top: 6em;
-}
-
-form.login {
-	margin: auto;
-	width: 18em;
-	padding: 1em;
-}	
-
-form.login label {
-	width: 5em;
-	text-align: right;
-	display: block;
-	float: left;
-	margin-bottom: 10px;
-	margin-top: 7px;
-}
-		
-form.login input {
-	float: left;
-	margin-left: 1em;
-	font-size: 100%;
-}
-
-form.login br {
-	clear: left;
-}
-
-form.login input#submit {
-	margin-left: 6em;;
-}
-
-p.login {
-	text-align: center;
-}
-
-p.login a {
-	background: none;
-	color: #D45E08;
-}
-
-p.login a:hover {
-	color: #E69200;
-}
-
-form#logoutform {
-	position: absolute;
-	bottom: 5px;
-	right: 5px;
-	width: 11em;
-	height: 4em;
-	text-align: center;
-	padding: 0;
-}
-
-.msgpoll {
-	clear: both;
-}
-
-.timestamp {
-	float: left;
-	width: 3.5em;
-}
-
-.msg_poster {
-	float: left;
-	display: block;
-	width: 9.5em;
-	text-align: right;
-}
-
-.msg_content {
-	padding-left: 10em;
-	text-indent: -1.2em;
-	display: block;
-	word-wrap: break-word;
-}
-
-.msg_content.withts {
-	padding-left: 14.2em;
-}
-
-/* ************************************ */
-/* * Message CSS                      * */
-/* ************************************ */
-
-.msgpoll.user_System {
-	font-weight: bold;
-}
-
-/* ************************************************* */
-/* * Term Colours (Silver on Black)                * */
-/* ************************************************* */
-
-#textlist, #textlist table, a {
-	background: #000000;
-	color: #d6d6d6;
-}
-
-.bold {
-	font-weight: bold;
-}
-
-.colourfgr {
-	color: #d0301f;
-}
-.colourfgg {
-	color: #00b943;
-}
-.colourfgb {
-	color: #3948da;
-}
-.colourfgc {
-	color: #00bcc8;
-}
-.colourfgy {
-	color: #b1aa3f;
-}
-.colourfgm {
-	color: #de47cc;
-}
-
-.colourfgw {
-	color: #cacccd;
-}
-
-.colourfgk {
-	color: #000000;
-}
-
-.colourbgr {
-	background: #a40302;
-}
-.colourbgg {
-	background: #039f30;
-}
-.colourbgb {
-	background: #022aa7;
-}
-.colourbgc {
-	background: #01a2ad;
-}
-.colourbgy {
-	background: #99922a;
-}
-.colourbgm {
-	background: #b924a8;
-}
-
-.colourbgw {
-	background: #d6d6d6;
-}
-
-.colourbgk {
-	background: #000000;
-}
-
-/* ************************************************* */
-/* * System Colours (Fry's Standard Colour Scheme) * */
-/* ************************************************* */
-
-.colour00 {
-}
-
-.colour01 {
-	font-weight: bold;
-	color: #de47cc;
-}
-
-.colour02 {
-	color: #de47cc;
-}
-
-.colour03 {
-	color: #d0301f;
-}
-
-.colour04 {
-	font-weight: bold;
-	color: #d0301f;
-}
-
-.colour05 {
-	font-weight: bold;
-	color: #3948da;
-}
-
-.colour06 {
-	font-weight: bold;
-	color: #d0301f;
-}
-
-.colour10 {
-	font-weight: bold;
-	color: #b1aa3f;
-}
-
-.colour11 {
-	color: #b1aa3f;
-}
-
-.colour12 {
-	font-weight: bold;
-	color: #00b943;
-}
-
-.colour13 {
-	color: #00b943;
-}
-
-.colour14 {
-	#cacccd;
-	font-weight: bold;
-}
-
-.colour15, .colour17 {
-	background-color: #0129a7;
-	font-weight: bold;
-	color: #b1aa3f;
-}
-
-.colour16 {
-	background-color: #0129a7;
-	font-weight: bold;
-	color: #cacccd;
-}
-
-.colour18 {
-	background-color: #0129a7;
-	font-weight: bold;
-	color: #d0301f;
-}
-
-.colour19 {
-	background-color: #0129a7;
-	font-weight: bold;
-	color: #00bcc8;
-}
-
-.colour20 {
-	background-color: #0129a7;
-	font-weight: bold;
-	color: #de47cc;
-}
-
-/* ************************************************* */
-/* * User Colours                                  * */
-/* ************************************************* */
-
-.user_0 .timestamp, .user_0 .msg_poster, .who.user_0 {color: #c00;}
-.user_1 .timestamp, .user_1 .msg_poster, .who.user_1 {color: #0c0;}
-.user_2 .timestamp, .user_2 .msg_poster, .who.user_2 {color: #33f;}
-.user_3 .timestamp, .user_3 .msg_poster, .who.user_3 {color: #0aa;}
-.user_4 .timestamp, .user_4 .msg_poster, .who.user_4 {color: #aa0;}
-.user_5 .timestamp, .user_5 .msg_poster, .who.user_5 {color: #a0a;}
-.user_6 .timestamp, .user_6 .msg_poster, .who.user_6 {color: #8d0;}
-.user_7 .timestamp, .user_7 .msg_poster, .who.user_7 {color: #d80;}
-.user_8 .timestamp, .user_8 .msg_poster, .who.user_8 {color: #d08;}
-.user_9 .timestamp, .user_9 .msg_poster, .who.user_9 {color: #80d;}
-.user_10 .timestamp, .user_10 .msg_poster, .who.user_10 {color: #08d;}
-.user_11 .timestamp, .user_11 .msg_poster, .who.user_11 {color: #0d8;}
-.user_12 .timestamp, .user_12 .msg_poster, .who.user_12 {color: #6e0;}
-.user_13 .timestamp, .user_13 .msg_poster, .who.user_13 {color: #e60;}
-.user_14 .timestamp, .user_14 .msg_poster, .who.user_14 {color: #60e;}
-.user_15 .timestamp, .user_15 .msg_poster, .who.user_15 {color: #e06;}
-.user_16 .timestamp, .user_16 .msg_poster, .who.user_16 {color: #0e6;}
-.user_17 .timestamp, .user_17 .msg_poster, .who.user_17 {color: #06e;}
-
-
-/* ... */
-
-.idle {
-	background-color: #333;
-}


=====================================
webclient/person.png deleted
=====================================
Binary files a/webclient/person.png and /dev/null differ


=====================================
webclient/poll.php
=====================================
--- a/webclient/poll.php
+++ b/webclient/poll.php
@@ -2,14 +2,9 @@
 
 require_once("config.php");
 
-if (isset($_COOKIE['mwsess'])) {
-	$data = unserialize($_COOKIE['mwsess']);
-	$sess = (int)$data['pid'];
-	$auth = trim($data['auth']);
-} else {
-	$sess = (int)@$_REQUEST['sess'];
-	$auth = trim(@$_REQUEST['auth']);
-}
+$data = unserialize(@$_REQUEST['mwsess']);
+$sess = (int)$data['pid'];
+$auth = trim($data['auth']);
 
 $path = $poller_path.$sess;
 
@@ -17,38 +12,38 @@ header("Content-type: application/json; charset=utf-8");
 
 $sock = socket_create(AF_UNIX, SOCK_SEQPACKET, 0);
 if (@socket_connect($sock, $path) === FALSE) {
-	echo "{\"status\":\"Socket open error\"}\n";
-	exit;
+  echo "{\"status\":\"Socket open error\"}\n";
+  exit;
 }
 
 $msg = "auth $auth";
 if (@socket_send($sock, $msg, strlen($msg), 0)===FALSE) {
-	echo "{\"status\":\"Socket error\"}\n";
-	exit;
+  echo "{\"status\":\"Socket error\"}\n";
+  exit;
 }
 
 if (@socket_recv($sock, $response, 4096, 0)===FALSE) {
-	echo "{\"status\":\"Socket error\"}\n";
-	exit;
+  echo "{\"status\":\"Socket error\"}\n";
+  exit;
 }
 $res = json_decode($response, TRUE);
 if ($res === NULL) { echo "{\"status\":\"Bad server response\"}\n"; exit; }
 
 if ($res['status'] != "OK") {
-	echo $response;
-	exit;
+  echo $response;
+  exit;
 }
 
 $msg = "fetch";
 
 if (@socket_send($sock, $msg, strlen($msg), MSG_EOF)===FALSE) {
-	echo "{\"status\":\"Socket error\"}\n";
-	exit;
+  echo "{\"status\":\"Socket error\"}\n";
+  exit;
 }
 
-if (@socket_recv($sock, $response, 8192, 0)===FALSE) {
-	echo "{\"status\":\"Socket error\"}\n";
-	exit;
+if (@socket_recv($sock, $response, 262144, 0)===FALSE) {
+  echo "{\"status\":\"Socket error\"}\n";
+  exit;
 }
 
 if ($response!="") echo $response."\n";


=====================================
webclient/say.js deleted
=====================================
--- a/webclient/say.js
+++ /dev/null
@@ -1,443 +0,0 @@
-var die=0;
-
-
-function pageInit() {
-	sendCmdHandle('who', drawWhoList);
-	sendCmdHandle('whoami', userProfile);
-	var sayit = document.getElementById("sayit");
-	sayit.focus();
-}
-
-	function addmsg(type, msg) {
-		var tmo = 500;
-
-		if (type != "poll") {
-			$("#textlist").append( "<div class='msg"+type+"'>"+msg+ "</div");
-		} else
-		if (msg.status) {
-			tmo = 10000;
-			if (msg.status == "Socket open error") {
-				$("#textlist").append( "<div class='msg"+type+"'><b><i>Session Closed</i></b></div");
-				tmo = 0;
-			}else {
-				$("#textlist").append( "<div class='msg"+type+"'>Problem: " + msg.status + "</div");
-			}
-		} else {
-			for (one in msg) {
-				switch (msg[one].state) {
-				case "SAYR":
-                case "SAYU":
-					// decode the json message
-					var detail = JSON.parse(msg[one].text);
-
-					var body = detail.text;
-					// make a crude approximation of the old message styles
-					switch (detail.type) {
-						case "say":
-							body = msg[one].name + ": " + detail.text;
-							break;
-						case "raw":
-							body = detail.text;
-							break;
-						case "emote":
-							switch (detail.plural){
-								case 1:
-									body = msg[one].name + "'s " + detail.text;
-									break;
-								case 2:
-									body = msg[one].name + "' " + detail.text;
-									break;
-								case 3:
-									body = msg[one].name + "'d " + detail.text;
-									break;
-								case 4:
-									body = msg[one].name + "'ll " + detail.text;
-									break;
-								default:
-									body = msg[one].name + " " + detail.text;
-									break;
-							}
-							break;
-						case "notsayto":
-							body = msg[one].name + " says (-" + detail.exclude + "): " + detail.text;
-							break;
-						case "says":
-							body = msg[one].name + " says: " + detail.text;
-							break;
-						case "whispers":
-							body = msg[one].name + " whispers: " + detail.text;
-							break;
-						default:
-							body = msg[one].name + " " + detail.text;
-							break;
-					}
-
-					/* Escape HTML characters */
-					var escapedMsg = body.replace(/&/g, "&");
-					escapedMsg = escapedMsg.replace(/</g, "<");
-					escapedMsg = escapedMsg.replace(/>/g, ">");
-					escapedMsg = escapedMsg.replace(/\n/g, "");
-					escapedMsg = escapedMsg.replace(/\r/g, "");
-
-					/* Detect URIs and convert to links */
-					var uris = escapedMsg.match(/https?:\/\/[^ ]*/g);
-					for (thisuri in uris) {
-						escapedMsg = escapedMsg.replace(uris[thisuri], "<a target=\"_new\" href=\""+uris[thisuri]+"\">"+uris[thisuri]+"</a>");
-					}
-
-					/* Insert timestamp if necessary */
-					var timestamp="";
-					if (userProfile.special.match("t")) {
-						var currentTime = new Date();
-						var withts=" withts";
-						timestamp = "<span class=\"timestamp\">"+pad(currentTime.getHours(), 2)+":"+pad(currentTime.getMinutes(), 2)+" </span>";
-					}
-
-					/* Detect username */
-					if (escapedMsg.substr(0, msg[one].name.length)==msg[one].name) {
-						escapedMsg = escapedMsg.replace(msg[one].name, "<span class='msg_poster'>"+msg[one].name+"</span><span class='msg_content"+withts+"'><span>");
-						escapedMsg = escapedMsg+"</span></span>";
-					}
-				
-					/* Replace colour codes with appropriate span tags */				
-					var msgColours = escapedMsg.match(/\u001b../g);
-					if (msgColours != null) {
-						for (i=0;i<msgColours.length;i++) {
-							if (isNaN(msgColours[i].charAt(1))) {
-								var colourBold = "";
-								var fgColour = msgColours[i].charAt(1);
-								if (fgColour!=fgColour.toLowerCase()) { colourBold = " bold"; }
-								escapedMsg = escapedMsg.replace(msgColours[i], "</span><span class='colourfg"+msgColours[i].charAt(1)+colourBold+" colourbg"+msgColours[i].charAt(2)+"'>");
-							} else {
-								escapedMsg = escapedMsg.replace(msgColours[i], "</span><span class='colour"+msgColours[i].replace(/\u001b/g, "")+"'>");
-							}
-						}
-					}
-
-					/* Output the processed line */
-					$("#textlist").append( "<p class='msg"+type+" user_"+userIndex[msg[one].name.toLowerCase()]+"'>" + timestamp + escapedMsg + "</p");
-
-					break;
-
-				case 11: // Talker message
-				case 17: // Board Message
-				/* Escape HTML characters */
-					var escapedMsg = msg[one].text.replace(/&/g, "&");
-					escapedMsg = escapedMsg.replace(/</g, "<");
-					escapedMsg = escapedMsg.replace(/>/g, ">");
-					escapedMsg = escapedMsg.replace(/\n/g, "");
-					escapedMsg = escapedMsg.replace(/\r/g, "");
-
-				/* Detect URIs and convert to links */
-					var uris = escapedMsg.match(/https?:\/\/[^ ]*/g);
-					for (thisuri in uris) {
-						escapedMsg = escapedMsg.replace(uris[thisuri], "<a target=\"_new\" href=\""+uris[thisuri]+"\">"+uris[thisuri]+"</a>");
-					}
-
-				/* Insert timestamp if necessary */
-					var timestamp="";
-					if (userProfile.special.match("t")) {
-						var currentTime = new Date();
-						var withts=" withts";
-						timestamp = "<span class=\"timestamp\">"+pad(currentTime.getHours(), 2)+":"+pad(currentTime.getMinutes(), 2)+" </span>";
-					}
-
-				/* Detect username */
-					if (escapedMsg.substr(0, msg[one].name.length)==msg[one].name) {
-						escapedMsg = escapedMsg.replace(msg[one].name, "<span class='msg_poster'>"+msg[one].name+"</span><span class='msg_content"+withts+"'><span>");
-						escapedMsg = escapedMsg+"</span></span>";
-					}
-
-				/* Replace colour codes with appropriate span tags */				
-					var msgColours = escapedMsg.match(/\u001b../g);
-					if (msgColours != null) {
-						for (i=0;i<msgColours.length;i++) {
-							if (isNaN(msgColours[i].charAt(1))) {
-								var colourBold = "";
-								var fgColour = msgColours[i].charAt(1);
-								if (fgColour!=fgColour.toLowerCase()) { colourBold = " bold"; }
-								escapedMsg = escapedMsg.replace(msgColours[i], "</span><span class='colourfg"+msgColours[i].charAt(1)+colourBold+" colourbg"+msgColours[i].charAt(2)+"'>");
-							} else {
-								escapedMsg = escapedMsg.replace(msgColours[i], "</span><span class='colour"+msgColours[i].replace(/\u001b/g, "")+"'>");
-							}
-						}
-					}
-
-				/* Output the processed line */
-					$("#textlist").append( "<p class='msg"+type+" user_"+userIndex[msg[one].name.toLowerCase()]+"'>" + timestamp + escapedMsg + "</p");
-
-					break;
-				case 14: // IPC_KICK
-					var what = "<div class='msgkick user_system'>";
-					if (msg[one].text.substr(0,1) == "m") {
-						what += "Boing, Zebedee's arrived. \"Look up!\" says Zebedee<br />";
-						what += "You look up; a large object is falling towards you very fast, very very fast. It looks like a Magic Roundabout!<br />";
-						what += "\"I wouldn't stand there if I was you\" says Zebedee<br />";
-						what += "WWWHHHEEEEEEEKKKKEEEERRRRRUUUUUNNNNNCCCCCHHHHHH<br />";
-						what += msg[one].name + " has just dropped the Magic Roundabout of Death on you.<br />";
-					} else {
-						what += "Boing, Zebedee arrived.<br />";
-						what += "\"Time for bed\" says Zebedee<br />";
-						what += msg[one].name + " has just dropped the Zebedee of Death on you.<br />";
-					}
-					if (msg[one].text.substr(1,1) == 'r') what += "\""+msg[one].text.substr(2)+"\" says Zebedee<br />";
-					what += "</div>";
-					$("#textlist").append(what);
-					break;
-				case 23: // CheckOnOff
-					sendCmdHandle('who', drawWhoList);
-					break;
-				default: 
-					what = "<div class='msg"+type+"'>";
-					what += "Unknown message type '"+msg[one].state+"' body='"+msg[one].text+"'";
-					what += "</div>";
-					$("#textlist").append(what);
-					break;
-				}
-			}
-		}
-		var objDiv = document.getElementById("textlist");
-		if (objDiv!=null) objDiv.scrollTop = objDiv.scrollHeight;
-		return tmo;
-	}
-
-	function waitForMsg() {
-		$.ajax( {
-			type: "GET",
-			url: "poll.php",
-			async: true,
-			cache: false,
-			timeout: 50000,
-			success: function(data) {
-				var tmo = addmsg("poll", data);
-				if (tmo>0) setTimeout( 'waitForMsg()', tmo);
-			},
-			error: function(XMLHttpRequest, textStatus, errorThrown){
-				var tmo = addmsg("error", textStatus+" ("+errorThrown+")");
-				if (tmo>0) setTimeout('waitForMsg()', tmo);
-			}
-		});
-	}
-
-function sendSay(text)
-{
-	if (text.substr(0, 1)=="."||text.substr(0, 1)=="!"||text.substr(0, 1)=="/") {
-		cmdParser(text);
-		return false;
-	}
-
-	var what = "say "+text;
-	$.getJSON("send.php", {send: what}, function(data, stats) {
-		});
-	return false;
-}
-
-function cmdParser(text) {
-	if (text.search(" ")==-1) {
-		var cmd = text.substring(1);
-	} else {
-		var cmd = text.substring(1, text.search(" "));
-		var args = text.substring(text.search(" ")+1);
-	}
-
-	switch(cmd) {
-	case "who":
-		sendCmdHandle('who', drawWho);
-		break;
-	case "room":
-                if (args == undefined || args < 0 || args > 65535){
-                        $('#textlist').append("<div class='error'>Usage: "+cmd+" <number></div>");
-                }else{
-			sendCmd('channel '+args);
-                }
-		break;
-	case "e":
-	case "em":
-	case "emote":
-	case "me":
-		var what = "emote "+args;
-		if (args == undefined){
-			$('#textlist').append("<div class='error'>Usage: "+cmd+" <text></div>");
-		}else{
-	                $.getJSON("send.php", {send: what});
-		}
-		break;
-	case "sayto":
-	case "sa":
-	case "whisper":
-	case "whi":
-		var what = "sayto "+args;
-                if (args == undefined){
-			$('#textlist').append("<div class='error'>Usage: "+cmd+" <user> <text></div>");
-		}else{
-		        $.getJSON("send.php", {send: what});
-		}
-
-		break;
-	case "q":
-	case "qq":
-	case "quit":
-		sendCmd('quit');
-		window.location = 'index.php?action=logout'
-		break;
-	}
-}
-
-function drawTime(time) {
-	var days = time/86400;
-	var hours = (time%86400)/3600;
-	var minutes = ((time%86400)%3600)/60;
-	var seconds = ((time%86400)%3600)%60;
-	var text = "";
-	if (days>=2) text += parseInt(days)+"d";
-	if (hours>=1) text += parseInt(hours)+"h";
-	if (minutes>=1&&days<2) text += parseInt(minutes)+"m";
-	if (hours<1) text += seconds+"s";
-	return text;
-}
-
-function drawWho(data, stat)
-{
-        var text = "<hr /><table cellspacing=\"0\" cellpadding=\"0\"><tbody>";
-        text += "<tr><th style=\"width: 10em;\">Name</th><th style=\"width: 6em;\">Idle</th><th>What...</th></tr>";
-        for (person in data) {
-		var line = "<td>"+data[person].name+"</td>";
-		line += "<td>"+drawTime(data[person].idletime)+"</td>";
-		line += "<td>Room "+data[person].channel+"</td>";
-		text += "<tr>"+line+"</tr>";
-        }
-        text += "</tbody></table><hr />";
-        addmsg("who", text);
-}
-
-function sortWho(a, b) {
-	var nameA=a.name.toLowerCase(), nameB=b.name.toLowerCase();
-	if (nameA < nameB) return -1;
-	if (nameA > nameB) return 1;
-	return 0;
-}
-
-// For debugging purposes
-function concatObject(obj) {
-  str='';
-  for(prop in obj)
-  {
-    str+=prop + " => "+ obj[prop]+"\n";
-  }
-  return(str);
-}
-
-function userInit(data, stat) {
-	userIndex=new Object;
-	data.sort(sortWho);
-	usercount=0;
-	for (var person in data) {
-		var thisUsername=data[person].name.toLowerCase();
-		if (thisUsername in userIndex) usercount--;
-		userIndex[thisUsername]=usercount;
-		usercount++;
-	}
-}
-
-function userAdd(data, stat) {
-	for (var person in data) {
-		var thisUsername=data[person].name.toLowerCase();
-		if (!(thisUsername in userIndex)) {
-			userIndex[thisUsername]=usercount;
-			usercount++;
-		}
-	}
-}
-
-function drawWhoList(data, stat) {
-	var idleness;
-	if(typeof userIndex == "undefined") userInit(data, stat);
-	else userAdd(data, stat);
-
-	$("li").remove();
-	data.sort(sortWho);
-	for (var person in data) {
-		idleness="";
-		if (data[person].idletime>1800) idleness=" idle";
-		var thisUsername=data[person].name.toLowerCase();
-		var personinfo = "<div class=\"whoinfo\">";
-		if (data[person].hgwidth>0) personinfo += "<img src=\"https://sucs.org/pictures/people/"+data[person].name.toLowerCase()+".png\" width=\""+data[person].hgwidth+"\" height=\"64\" />";
-		else personinfo += "<img src=\"person.png\" width=\"64\" height=\"64\" />";
-		personinfo += "<strong>"+data[person].name+"</strong>";
-		personinfo += " "+data[person].doing;
-		personinfo += "<br />";
-		if (data[person].realname!=undefined) personinfo += data[person].realname+"<br />";
-		personinfo += "Room "+data[person].channel;
-		personinfo += "</div>";
-		$("#wholist").append("<li class=\"who user_"+userIndex[thisUsername]+idleness+"\"><a href=\"#\">"+data[person].name+personinfo+"</a></li>");
-	}
-}
-
-function userProfile(data, stat) {
-	userProfile=new Object;
-	for (var item in data) {
-		userProfile[item] = data[item];
-	}
-}
-
-function sendCmdHandle(cmd, handle)
-{
-	$.getJSON("send.php", {send: cmd}, handle);
-}
-
-function sendCmd(cmd) {
-	$.getJSON("send.php", {send: cmd});
-}
-
-function pad(number, length) {
-    var str = '' + number;
-    while (str.length < length) {
-        str = '0' + str;
-    }
-    return str;
-}
-
-function submitenter(myfield,e) {
-	var keycode;
-	if (window.event) keycode = window.event.keyCode;
-	else if (e) keycode = e.which;
-	else return true;
-	switch (keycode) {
-	case 13:
-		var text = $('#sayit').val();
-		$('#sayit').val("");
-		sendSay(text);
-		return false;
-	case 27:
-		insertEscape(false);
-		return false;
-	default:
-		return true;
-	}
-}
-
-function insertEscape(buttonpress) {
-var myField=document.getElementById("sayit");
-var myValue="\033";
-  //IE support
-  if (document.selection) {
-    myField.focus();
-    sel = document.selection.createRange();
-    sel.text = myValue;
-  }
-  //MOZILLA/NETSCAPE support
-  else if (myField.selectionStart || myField.selectionStart == '0') {
-    var startPos = myField.selectionStart;
-    var endPos = myField.selectionEnd;
-    myField.value = myField.value.substring(0, startPos)
-                  + myValue
-                  + myField.value.substring(endPos, myField.value.length);
-    myField.selectionStart = startPos+1;
-    myField.selectionEnd = myField.selectionStart;
-  } else {
-    myField.value += myValue;
-  }
-	if (buttonpress) myField.focus();
-}
-
-$(document).ready(function(){waitForMsg();});


=====================================
webclient/send.php
=====================================
--- a/webclient/send.php
+++ b/webclient/send.php
@@ -1,79 +1,81 @@
 <?
+header('Access-Control-Allow-Headers: Access-Control-Allow-Headers, Origin,Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers');
 
 require_once("config.php");
 
-if (isset($_COOKIE['mwsess'])) {
-	$data = unserialize($_COOKIE['mwsess']);
-	$sess = (int)$data['pid'];
-	$auth = trim($data['auth']);
-} else {
-	$sess = (int)@$_REQUEST['sess'];
-	$auth = trim(@$_REQUEST['auth']);
-}
+$_REQUEST = json_decode(file_get_contents('php://input'), true);
+
+$data = unserialize($_REQUEST['mwsess']);
+$sess = (int)$data['pid'];
+$auth = trim($data['auth']);
 
 $path = $poller_path.$sess;
 
 header("Content-type: application/json");
 
 if (!isset($_REQUEST['send'])) {
-	echo "{\"status\":\"Bad command\"}\n";
-	exit;
+  echo "{\"status\":\"Bad command\"}\n";
+  exit;
 }
 
 $sock = socket_create(AF_UNIX, SOCK_SEQPACKET, 0);
 if (@socket_connect($sock, $path) === FALSE) {
-	echo "{";
-	echo "\"status\":\"Socket open error\"";
-	$err = error_get_last();
-	echo ",\"detail\":\"".$err['message']."\"";
-	echo ",\"path\":\"".$path."\"";
-	echo "}\n";
-	exit;
+  echo "{";
+  echo "\"status\":\"Socket open error\"";
+  $err = error_get_last();
+  echo ",\"detail\":\"".$err['message']."\"";
+  echo ",\"path\":\"".$path."\"";
+  echo "}\n";
+  exit;
 }
 
 $msg = "auth $auth";
 if (@socket_send($sock, $msg, strlen($msg), 0)===FALSE) {
-	echo "{\"status\":\"Socket error\"}\n";
-	exit;
+  echo "{\"status\":\"Socket error\"}\n";
+  exit;
 }
 
 if (@socket_recv($sock, $response, 4096, 0)===FALSE) {
-	echo "{\"status\":\"Socket error\"}\n";
-	exit;
+  echo "{\"status\":\"Socket error\"}\n";
+  exit;
 }
+
 $res = json_decode($response, TRUE);
-if ($res === NULL) { echo "{\"status\":\"Bad server response\"}\n"; exit; }
+if ($res === NULL) {
+  echo "{\"status\":\"Bad server response\"}\n";
+  exit;
+}
 
 if ($res['status'] != "OK") {
-	echo $response;
-	exit;
+  echo $response;
+  exit;
 }
 
 $msg = trim($_REQUEST['send']);
 
 if (@socket_send($sock, $msg, strlen($msg), MSG_EOF)===FALSE) {
-	echo "{\"status\":\"Socket error\"}\n";
-	exit;
+  echo "{\"status\":\"Socket error\"}\n";
+  exit;
 }
 
 if (@socket_recv($sock, $response, 8192, 0)===FALSE) {
-	echo "{\"status\":\"Socket error\"}\n";
-	exit;
+  echo "{\"status\":\"Socket error\"}\n";
+  exit;
 }
 
 if ($_REQUEST['send']=="who") {
-	$who = json_decode($response, TRUE);
-	$pcount=0;
-	foreach ($who as $person) {
-		$im_file = "/var/www/sucssite/htdocs/pictures/people/".strtolower($person['username']).".png";
-		if (file_exists($im_file)) {
-			$size = getimagesize($im_file);
-			$factor = 64/$size[1];
-			$who[$pcount]['hgwidth']=(int)($size[0]*$factor);
-		}
-		$pcount++;
-	}
-	$response = json_encode($who);
+  $who = json_decode($response, TRUE);
+  $pcount=0;
+  foreach ($who as $person) {
+    $im_file = "/var/www/sucssite/htdocs/pictures/people/".strtolower($person['username']).".png";
+    if (file_exists($im_file)) {
+      $size = getimagesize($im_file);
+      $factor = 64/$size[1];
+      $who[$pcount]['hgwidth']=(int)($size[0]*$factor);
+    }
+    $pcount++;
+  }
+  $response = json_encode($who);
 }
 
 echo $response."\n";


=====================================
webclient/startup.php
=====================================
--- a/webclient/startup.php
+++ b/webclient/startup.php
@@ -5,157 +5,142 @@ $mwpoll = $poller_bin;
 $username = trim($_REQUEST['username']);
 $password = trim($_REQUEST['password']);
 
-### Preliminary checks
+// Preliminary checks
 
-# Have we been passed SUCSsite cookies?
-# If not, test that the login details make sense.
+// Have we been passed SUCSsite cookies?
+// If not, test that the login details make sense.
 if (@$_REQUEST['sucssite_loggedin']!="true") {
-	if (empty($username) || empty($password)) {
-		$smarty->assign("error", "username and password must both be not empty");
-		$smarty->assign("body", $smarty->fetch("login.html"));
-		$smarty->display("main.html");
-		exit;
-	}
-
-	if (ctype_alnum($username) === FALSE) {
-		$smarty->assign("error", "alphanumeric usernames only");
-		$smarty->assign("body", $smarty->fetch("login.html"));
-		$smarty->display("main.html");
-		exit;
-	}
+  if (empty($username) || empty($password)) {
+    echo json_encode((object) ['error' => 'username and password must both be not empty']);
+    exit;
+  }
+
+  if (ctype_alnum($username) === FALSE) {
+    echo json_encode((object) ['error' => 'alphanumeric usernames only']);
+    exit;
+  }
 }
 
-# Have we been asked to create a new Milliways account?
-# If so, make sure that the password supplied is suitable.
+// Have we been asked to create a new Milliways account?
+// If so, make sure that the password supplied is suitable.
 if ($action=="create") {
-	$pass1 = @$_REQUEST['password1'];
-	$pass2 = @$_REQUEST['password2'];
-	if ($pass1 != $pass2) {
-		$smarty->assign("error", "Passwords don't match - please try again");
-		$smarty->assign("body", $smarty->fetch("createaccount.html"));
-		$smarty->display("main.html");
-		exit;	
-	}
-	if (empty($pass1)) {
-		$smarty->assign("error", "Password cannot be blank");
-		$smarty->assign("body", $smarty->fetch("createaccount.html"));
-		$smarty->display("main.html");
-		exit;	
-	}
-	if (ctype_alnum($pass1) === FALSE) {
-		$smarty->assign("error", "Milliways passwords can only contain alphanumeric characters");
-		$smarty->assign("body", $smarty->fetch("createaccount.html"));
-		$smarty->display("main.html");
-		exit;	
-	}
-	if (strlen($pass1) < 6) {
-		$smarty->assign("error", "Milliways passwords must be 6 characters or more");
-		$smarty->assign("body", $smarty->fetch("createaccount.html"));
-		$smarty->display("main.html");
-		exit;	
-	}
+  $pass1 = @$_REQUEST['password1'];
+  $pass2 = @$_REQUEST['password2'];
+  
+  if ($pass1 != $pass2) {
+    echo json_encode((object) ['error' => 'Passwords don\'t match - please try again']);
+    exit;	
+  }
+
+  if (empty($pass1)) {
+    echo json_encode((object) ['error' => 'Password cannot be blank']);
+    exit;	
+  }
+	
+  if (ctype_alnum($pass1) === FALSE) {
+    echo json_encode((object) ['error' => 'Milliways passwords can only contain alphanumeric characters']);
+    exit;	
+  }
+
+  if (strlen($pass1) < 6) {
+    echo json_encode((object) ['error' => 'Milliways passwords must be 6 characters or more']);
+    exit;	
+  }
 }
 
 $desc = array( 
-	0 => array("pipe", "r"),
-	1 => array("pipe", "w"),
+  0 => array("pipe", "r"),
+  1 => array("pipe", "w"),
 );
 $pipes = array();
 
-# Have we got SUCSsite cookies?
-# And no login attempt?
-# If so, fetch the user details and try to log in without a password.
+// Have we got SUCSsite cookies?
+// And no login attempt?
+// If so, fetch the user details and try to log in without a password.
 if (@$_REQUEST['sucssite_loggedin']=="true" && empty($username)) {
-# Do we appear to be in the SUCSsite environment?
-# There's only any point trying if we do.
-if (file_exists("../settings.php")) {
-	# Do the bare minimum of SUCSsite init to retrieve the username for the session we've been passed
-	include("../settings.php");
-	// Initialise the database
-	require("/usr/share/php/adodb/adodb.inc.php");
-	$DB = NewADOConnection('postgres9');
-	$DB->Connect('dbname='.$dbname.' user=apache');
-	$DB->SetFetchMode(ADODB_FETCH_ASSOC);
+
+  // Do we appear to be in the SUCSsite environment?
+  // There's only any point trying if we do.
+  if (file_exists("../settings.php")) {
+    // Do the bare minimum of SUCSsite init to retrieve the username for the session we've been passed
+    include("../settings.php");
+    // Initialise the database
+    require("/usr/share/php/adodb/adodb.inc.php");
+    $DB = NewADOConnection('postgres9');
+    $DB->Connect('dbname='.$dbname.' user=apache');
+    $DB->SetFetchMode(ADODB_FETCH_ASSOC);
 	
-	// Include the session library
-	require($base."lib/session.php");
-	$session = new Session;
-	$smarty->assign("session", $session);
-	$realuser = $session->username;
-
-	if ($action == "create") {
-		$p = proc_open($mwpoll." -a -u ".$realuser." -s", $desc, $pipes);	
-	} else {
-		$p = proc_open($mwpoll." -u ".$realuser." -s", $desc, $pipes);
-	}
-	$mode = "sucssite";
-}
+    // Include the session library
+    require($base."lib/session.php");
+    $session = new Session;
+    // $smarty->assign("session", $session); // This line might be useful?
+    $realuser = $session->username;
+
+    if ($action == "create") {
+      $p = proc_open($mwpoll." -q -a -u ".$realuser." -s", $desc, $pipes);
+    } else {
+      $p = proc_open($mwpoll." -q -u ".$realuser." -s", $desc, $pipes);
+    }
+    $mode = "sucssite";
+  }
 } else {
-# If not, try logging in with a password.
-	$p = proc_open($mwpoll." -u $username", $desc, $pipes);
-	$mode = "password";
+  // If not, try logging in with a password.
+  $p = proc_open($mwpoll." -q -u $username", $desc, $pipes);
+  $mode = "password";
 }
 
 if (empty($p)) {
-	$smarty->assign("body", $smarty->fetch("login.html"));
-	$smarty->display("main.html");
-	exit;
+  echo "<h1>No</h1>";	
+  exit;
 }
 
 if ($p === FALSE) {
-	$smarty->assign("error", "failed to exec mwpoll");
-	$smarty->assign("body", $smarty->fetch("login.html"));
-	$smarty->display("main.html");
-	exit;
+  echo json_encode((object) ['error' => 'failed to exec mwpoll']);
+  exit;
 }
 
 if ($mode == "sucssite" && @$_REQUEST['sucssite_loggedin']=="true" && empty($username)) {
-// If we have a sucssite session cookie, use that
-	fwrite($pipes[0], trim($_REQUEST['sucssite_session'])."\n");
-	if ($action="create") {
-		fwrite($pipes[0], $pass1."\n");
-	}
+  // If we have a sucssite session cookie, use that
+  fwrite($pipes[0], trim($_REQUEST['sucssite_session'])."\n");
+  if ($action="create") {
+    fwrite($pipes[0], $pass1."\n");
+  }
 } else {
-// Try logging on using username and password
-	if (fwrite($pipes[0], $password."\n") === FALSE) {
-		echo "Error writing to mwpoll\n";
-	}
+  // Try logging on using username and password
+  if (fwrite($pipes[0], $password."\n") === FALSE) {
+    echo "Error writing to mwpoll\n";
+  }
 }
 
 $pid = fgets($pipes[1]);
 if ($pid === FALSE) {
-	echo "error reading pid.\n";
+  echo "error reading pid.\n";
 }
 
 $pid = trim($pid);
 if (!is_numeric($pid)) {
-	if (substr($pid, -10) =="not found.") {
-	// User doesn't exist - ask for a Milliways password so we can create them!
-		$smarty->assign("error", $pid);
-		$smarty->assign("body", $smarty->fetch("createaccount.html"));
-		$smarty->display("main.html");
-		exit;	
-	}
-	$smarty->assign("error", "Bad response: pid=$pid");
-	$smarty->assign("body", $smarty->fetch("login.html"));
-	$smarty->display("main.html");
-	exit;
+  if (substr($pid, -10) =="not found.") {
+    // User doesn't exist - ask for a Milliways password so we can create them!
+    echo json_encode((object) ['error' => $pid]);
+    exit;	
+  }
+
+  echo json_encode((object) ['error' => 'Bad response: pid=$pid']);
+  exit;
 }
 
 $auth = fgets($pipes[1]);
 
 if ($auth === FALSE) {
-	echo "Error reading auth string\n";
+  echo "Error reading auth string\n";
 }
 
 $sess = array (
-	"pid" => $pid,
-	"auth" => $auth,
-	"username" => $username
+  "pid" => $pid,
+  "auth" => $auth,
+  "username" => $username
 );
 
 $mwsess = serialize($sess);
-setcookie("mwsess", $mwsess);
-//$smarty->assign("debug", "Started new session pid=$pid auth=$auth");
-
+echo "success:" . $mwsess;
 ?>


=====================================
webclient/templates/createaccount.html deleted
=====================================
--- a/webclient/templates/createaccount.html
+++ /dev/null
@@ -1,24 +0,0 @@
-<p>Please choose a password for Milliways</p>
-
-<form method=post action={$self}>
-<table>
-	<tr>
-		<td align="right">Password:</td>
-		<td>
-			<input type="password" name="password1" size="20">
-		</td>
-	</tr>
-	<tr>
-		<td align="right">Password again:</td>
-		<td>
-			<input type="password" name="password2" size="20">
-		</td>
-	</tr>
-	<tr>
-		<td colspan="2" align="center">
-			<input type="submit" name="submit" value="Create account">
-		</td>
-	</tr>
-</table>
-<input type="hidden" name="action" value="create">
-</form>


=====================================
webclient/templates/front.html deleted
=====================================
--- a/webclient/templates/front.html
+++ /dev/null
@@ -1,16 +0,0 @@
-<div id="textlist"><p class="welcome">Milliways III - Web Edition</p></div>
-
-<ul id="wholist">
-</ul>
-
-<form action="" id="sayform"><div id="sayouter"><textarea name="sayit" id="sayit" onKeyDown="return submitenter(this,event)"></textarea></div></form>
-
-<form action="{$self}" method="post" id="logoutform">
-	<input type="hidden" name="action" value="logout">
-	<input type="button" name="escape" value="Escape" onclick="insertEscape(true);"><br />
-	<input type="submit" name="submit" value="Logout" onclick="sendCmd('quit');">
-</form>
-
-<script language="javascript" type="text/javascript">
-	pageInit();
-</script>


=====================================
webclient/templates/login.html deleted
=====================================
--- a/webclient/templates/login.html
+++ /dev/null
@@ -1,8 +0,0 @@
-<h1 class="login">Milliways</h1>
-<form method="post" class="login" action="{$self}">
-	<label for="username">Username:</label><input type="text" id="username" name="username" size="20" /><br />
-	<label for="password">Password:</label><input type="password" id="password" name="password" size="20" /><br />
-	<input type="submit" id="submit" name="submit" value="Login" /><br />
-	<input type="hidden" name="action" value="login" />
-</form>
-<p class="login">New here? Read up on your <a href="https://sucs.org/Knowledge/Help/SUCS%20Services/Using%20Milliways/Milliways%20Etiquette" target="_new">Milliways etiquette</a>.</p>


=====================================
webclient/templates/main.html deleted
=====================================
--- a/webclient/templates/main.html
+++ /dev/null
@@ -1,15 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<title>Milliways Talker</title>
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
-<script type="text/javascript" src="jquery.js"></script>
-<script type="text/javascript" src="say.js"></script>
-<link rel="stylesheet" type="text/css" media="all" href="mw.css" />
-</head>
-<body>
-{if $error}<div style="color: #ff0000;">{$error}</div>{/if}
-{$body}
-{if $debug}<div style="color: #00ff00;">{$debug}</div>{/if}
-</body>
-</html>



View it on GitLab: https://projects.sucs.org/arthur/mw/compare/9e4be71fa54d09a17009dd36479231ab13beaee3...02fc046aad4c8f2eeed94e766ea3cfd4a092a628

---
View it on GitLab: https://projects.sucs.org/arthur/mw/compare/9e4be71fa54d09a17009dd36479231ab13beaee3...02fc046aad4c8f2eeed94e766ea3cfd4a092a628
You're receiving this email because of your account on projects.sucs.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.sucs.org/pipermail/mw-devel/attachments/20170720/ed6a83b7/attachment-0001.html>


More information about the mw-devel mailing list