Add AI prompt support in the source

parent ac3b4252
- If you need to rebuild the project, use always ./build.sh --clean && ./build.sh
- if you need to build the debian packages, use ./build.sh --debian
- when you finish a todo list and everything is complete, execute a git commit
- the html pages and the assets to add in wssshd are generated from the templates directory, using the script embed_assets.sh.
- the script embed_assets.sh is launched by the Makefile
- the Makefile is generated by the script configure.sh
- in wssshd webinterface, the vnc page and the rdp page uses different websocket implementation, looks at the specifics of web.c and vnc.c or rdp.c, the file websocket.c is user ALSO for the websockets in the communication port with wssshc and wsssht, if you modify something for vnc or rdp or anything in the web interface, don't break the implementation for the wssshc-wssshd-wsssht communication channel/protocol
...@@ -29,6 +29,8 @@ ...@@ -29,6 +29,8 @@
#include "html_pages/mstsc_page.h" #include "html_pages/mstsc_page.h"
#include "html_pages/novnc_css_page.h" #include "html_pages/novnc_css_page.h"
#include "novnc_asset_map.c" #include "novnc_asset_map.c"
#include "rdp_assets.h"
#include "rdp_asset_map.c"
// HTML pages are now defined in separate header files in html_pages/ directory // HTML pages are now defined in separate header files in html_pages/ directory
// This file now only contains fallback definitions for compatibility // This file now only contains fallback definitions for compatibility
...@@ -76,6 +78,9 @@ const char *get_embedded_asset(const char *path, size_t *size) { ...@@ -76,6 +78,9 @@ const char *get_embedded_asset(const char *path, size_t *size) {
const char *content = get_novnc_asset(path); const char *content = get_novnc_asset(path);
if (content && size) *size = strlen(content); if (content && size) *size = strlen(content);
return content; return content;
} else if (strncmp(path, "/rdp/", 5) == 0) {
const char *content = get_rdp_asset(path, size);
return content;
} }
return NULL; return NULL;
......
...@@ -225,6 +225,75 @@ static const char *mstsc_js = ""; ...@@ -225,6 +225,75 @@ static const char *mstsc_js = "";
EOF EOF
fi fi
# Embed RDP JS files
echo "Embedding RDP JS files..."
mkdir -p html_pages
# Generate rdp_assets.h
cat > rdp_assets.h << 'EOF'
#ifndef RDP_ASSETS_H
#define RDP_ASSETS_H
EOF
# Generate rdp_asset_map.c
cat > rdp_asset_map.c << 'EOF'
#include <string.h>
#include "rdp_assets.h"
const char *get_rdp_asset(const char *path, size_t *size) {
EOF
find templates/rdp -name "*.wasm" | sort | while read -r file; do
if [ -f "$file" ]; then
RELPATH=$(echo "$file" | sed 's|templates/rdp/||')
VARNAME=$(echo "$RELPATH" | sed 's|/|_|g; s|\.wasm$|_wasm|; s|\.|_|g')
HEADER_FILE="html_pages/rdp_${VARNAME}_page.h"
echo "Embedding $file as rdp_${VARNAME}"
# Create header with extern
cat > "$HEADER_FILE" << EOF
#ifndef RDP_${VARNAME^^}_PAGE_H
#define RDP_${VARNAME^^}_PAGE_H
extern const unsigned char rdp_${VARNAME}[];
extern const unsigned int rdp_${VARNAME}_len;
#endif /* RDP_${VARNAME^^}_PAGE_H */
EOF
# Add to rdp_assets.h
echo "#include \"html_pages/rdp_${VARNAME}_page.h\"" >> rdp_assets.h
# Embed binary file
xxd -i "$file" > temp_binary.h
# Rename the variables and add static
sed -i "s/templates_rdp_rdp_wasm/rdp_rdp_wasm/g" temp_binary.h
sed -i "s/unsigned char rdp_rdp_wasm\[\]/static unsigned char rdp_rdp_wasm[]/g" temp_binary.h
sed -i "s/unsigned int rdp_rdp_wasm_len/static unsigned int rdp_rdp_wasm_len/g" temp_binary.h
cat temp_binary.h >> rdp_asset_map.c
rm temp_binary.h
# Add to rdp_asset_map.c
echo " if (strcmp(path, \"/rdp/$RELPATH\") == 0) {" >> rdp_asset_map.c
echo " if (size) *size = rdp_${VARNAME}_len;" >> rdp_asset_map.c
echo " return (const char *)rdp_${VARNAME};" >> rdp_asset_map.c
echo " }" >> rdp_asset_map.c
fi
done
cat >> rdp_assets.h << 'EOF'
#endif /* RDP_ASSETS_H */
EOF
cat >> rdp_asset_map.c << 'EOF'
return NULL;
}
EOF
echo "RDP JS files embedded."
# Embed noVNC CSS # Embed noVNC CSS
if [ -f templates/novnc.css ]; then if [ -f templates/novnc.css ]; then
echo "Embedding novnc.css..." echo "Embedding novnc.css..."
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -18,8 +18,8 @@ ...@@ -18,8 +18,8 @@
#include "html_pages/novnc_input_fixedkeys_js_page.h" #include "html_pages/novnc_input_fixedkeys_js_page.h"
#include "html_pages/novnc_input_gesturehandler_js_page.h" #include "html_pages/novnc_input_gesturehandler_js_page.h"
#include "html_pages/novnc_input_keyboard_js_page.h" #include "html_pages/novnc_input_keyboard_js_page.h"
#include "html_pages/novnc_input_keysymdef_js_page.h"
#include "html_pages/novnc_input_keysym_js_page.h" #include "html_pages/novnc_input_keysym_js_page.h"
#include "html_pages/novnc_input_keysymdef_js_page.h"
#include "html_pages/novnc_input_util_js_page.h" #include "html_pages/novnc_input_util_js_page.h"
#include "html_pages/novnc_input_vkeys_js_page.h" #include "html_pages/novnc_input_vkeys_js_page.h"
#include "html_pages/novnc_input_xtscancodes_js_page.h" #include "html_pages/novnc_input_xtscancodes_js_page.h"
......
...@@ -7,7 +7,12 @@ ...@@ -7,7 +7,12 @@
<link rel="icon" href="/favicon.ico" type="image/x-icon"> <link rel="icon" href="/favicon.ico" type="image/x-icon">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet"> <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
<script src="/mstsc.js"></script> <script src="/rdp/rdp.wasm.js"></script>
<script src="/rdp/clipboard.js"></script>
<script src="/rdp/out_stream.js"></script>
<script src="/rdp/rdp_graphics.js"></script>
<script src="/rdp/reversed_layouts.js"></script>
<script src="/rdp/scancodes.js"></script>
<style> <style>
.navbar-brand { .navbar-brand {
font-weight: bold; font-weight: bold;
...@@ -26,7 +31,7 @@ ...@@ -26,7 +31,7 @@
max-height: none; max-height: none;
height: auto; height: auto;
} }
.rdp-container.full-size #mstsc_screen { .rdp-container.full-size #canvas {
min-width: fit-content; min-width: fit-content;
min-height: fit-content; min-height: fit-content;
} }
...@@ -129,10 +134,18 @@ ...@@ -129,10 +134,18 @@
.rdp-window.fullscreen .minimize-btn { .rdp-window.fullscreen .minimize-btn {
display: flex; display: flex;
} }
#mstsc_screen { #canvas {
width: 100%; width: 100%;
height: 100%; height: 100%;
} }
#canvasFocus {
width: 0px;
height: 0px;
position: absolute;
z-index: -10;
padding: 0;
margin: 0;
}
</style> </style>
</head> </head>
<body> <body>
...@@ -170,9 +183,9 @@ ...@@ -170,9 +183,9 @@
</div> </div>
<div class="window-content"> <div class="window-content">
<div id="rdp" class="rdp-container w-100"> <div id="rdp" class="rdp-container w-100">
<div id="mstsc_screen"> <canvas id="canvas" width="1024" height="768"></canvas><input id="canvasFocus" type="text"/>
<div id="mstsc_status">Click Connect to start RDP session</div> <div id="rdp_status" style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); text-align: center; color: #f8f8f2;">Click Connect to start RDP session</div>
<div id="mstsc_loading" style="display: none; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); text-align: center; color: #f8f8f2;"> <div id="rdp_loading" style="display: none; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); text-align: center; color: #f8f8f2;">
<div class="spinner-border text-primary mb-2" role="status"> <div class="spinner-border text-primary mb-2" role="status">
<span class="visually-hidden">Loading...</span> <span class="visually-hidden">Loading...</span>
</div> </div>
...@@ -185,13 +198,13 @@ ...@@ -185,13 +198,13 @@
</div> </div>
</div> </div>
</div> </div>
</div>
</div> </div>
</div> </div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script> <script>
let rdp = null; let rdpclient = null;
let socket = null;
let connected = false; let connected = false;
document.getElementById('connectBtn').addEventListener('click', connect); document.getElementById('connectBtn').addEventListener('click', connect);
...@@ -204,6 +217,10 @@ document.querySelector('.maximize-btn').addEventListener('click', toggleFullscre ...@@ -204,6 +217,10 @@ document.querySelector('.maximize-btn').addEventListener('click', toggleFullscre
document.querySelector('.minimize-btn').addEventListener('click', toggleFullscreen); document.querySelector('.minimize-btn').addEventListener('click', toggleFullscreen);
document.getElementById('zoomBtn').addEventListener('click', toggleZoom); document.getElementById('zoomBtn').addEventListener('click', toggleZoom);
// Input event handlers
let ecanvas = document.getElementById('canvas');
let ecanvasFocus = document.getElementById('canvasFocus');
function showNotification(message, type = 'info') { function showNotification(message, type = 'info') {
const notificationArea = document.getElementById('notification-area'); const notificationArea = document.getElementById('notification-area');
const notification = document.createElement('div'); const notification = document.createElement('div');
...@@ -236,7 +253,7 @@ function toggleFullscreen() { ...@@ -236,7 +253,7 @@ function toggleFullscreen() {
} }
function toggleZoom() { function toggleZoom() {
if (!rdp || !connected) return; if (!rdpclient || !connected) return;
const zoomBtn = document.getElementById('zoomBtn'); const zoomBtn = document.getElementById('zoomBtn');
const zoomIcon = zoomBtn.querySelector('i'); const zoomIcon = zoomBtn.querySelector('i');
...@@ -249,6 +266,11 @@ function toggleZoom() { ...@@ -249,6 +266,11 @@ function toggleZoom() {
zoomIcon.className = 'fas fa-search-plus'; zoomIcon.className = 'fas fa-search-plus';
rdpContainer.classList.remove('full-size'); rdpContainer.classList.remove('full-size');
// Enable scaling, disable clipping
if (rdpclient.scaleViewport !== undefined) {
rdpclient.scaleViewport = true;
}
showNotification('Switched to scaled view (fit to window)', 'info'); showNotification('Switched to scaled view (fit to window)', 'info');
} else { } else {
// Switch to full-size view with scrollbars // Switch to full-size view with scrollbars
...@@ -257,6 +279,11 @@ function toggleZoom() { ...@@ -257,6 +279,11 @@ function toggleZoom() {
zoomIcon.className = 'fas fa-search-minus'; zoomIcon.className = 'fas fa-search-minus';
rdpContainer.classList.add('full-size'); rdpContainer.classList.add('full-size');
// Disable scaling, enable clipping
if (rdpclient.scaleViewport !== undefined) {
rdpclient.scaleViewport = false;
}
showNotification('Switched to actual size view with scrollbars', 'info'); showNotification('Switched to actual size view with scrollbars', 'info');
} }
} }
...@@ -265,68 +292,92 @@ function connect() { ...@@ -265,68 +292,92 @@ function connect() {
if (connected) return; if (connected) return;
// Hide the status text and show loading message // Hide the status text and show loading message
document.getElementById('mstsc_status').style.display = 'none'; document.getElementById('rdp_status').style.display = 'none';
document.getElementById('mstsc_loading').style.display = 'block'; document.getElementById('rdp_loading').style.display = 'block';
document.getElementById('cancelConnectBtn').style.display = 'inline-block'; document.getElementById('cancelConnectBtn').style.display = 'inline-block';
const wsProtocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'; const wsProtocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
const wsUrl = wsProtocol + '//' + window.location.host + '/rdp/%s/ws'; const wsUrl = wsProtocol + '//' + window.location.host + '/rdp/%s/ws';
try { try {
rdp = new Mstsc(document.getElementById('mstsc_screen'), { socket = new WebSocket(wsUrl);
url: wsUrl, socket.binaryType = 'arraybuffer';
socket.onopen = () => {
const canvas = document.getElementById('canvas');
const gd = new GraphicsDevice(canvas);
const config = {
width: 1024, width: 1024,
height: 768, height: 768,
domain: '',
username: '', username: '',
password: '', password: '',
keyboard: true, domain: '',
mouse: true, bpp: 32,
clipboard: true verbosity: 0
}); };
rdpclient = new RdpClient(gd, config);
rdp.addEventListener('connect', () => { rdpclient.writeFirstPacket();
sendData();
connected = true; connected = true;
document.getElementById('connectBtn').disabled = true; document.getElementById('connectBtn').disabled = true;
document.getElementById('disconnectBtn').disabled = false; document.getElementById('disconnectBtn').disabled = false;
// Hide loading message // Hide loading message
document.getElementById('mstsc_loading').style.display = 'none'; document.getElementById('rdp_loading').style.display = 'none';
showNotification('RDP session connected', 'success'); showNotification('RDP session connected', 'success');
}); };
socket.onmessage = (event) => {
rdpclient.processInputData(event.data);
sendData();
};
rdp.addEventListener('disconnect', () => { socket.onclose = () => {
connected = false; connected = false;
document.getElementById('connectBtn').disabled = false; document.getElementById('connectBtn').disabled = false;
document.getElementById('disconnectBtn').disabled = true; document.getElementById('disconnectBtn').disabled = true;
// Reset UI to initial state // Reset UI to initial state
document.getElementById('mstsc_status').style.display = 'block'; document.getElementById('rdp_status').style.display = 'block';
document.getElementById('mstsc_loading').style.display = 'none'; document.getElementById('rdp_loading').style.display = 'none';
document.getElementById('cancelConnectBtn').style.display = 'none'; document.getElementById('cancelConnectBtn').style.display = 'none';
showNotification('RDP session disconnected', 'info'); showNotification('RDP session disconnected', 'info');
}); rdpclient = null;
socket = null;
};
rdp.addEventListener('error', (e) => { socket.onerror = (e) => {
console.error('RDP error:', e.detail); console.error('RDP WebSocket error:', e);
showNotification('RDP error: ' + e.detail, 'danger'); showNotification('RDP connection error', 'danger');
}); };
} catch (e) { } catch (e) {
console.error('Failed to create RDP client:', e); console.error('Failed to create RDP client:', e);
showNotification('Failed to connect RDP: ' + e.message, 'danger'); showNotification('Failed to connect RDP: ' + e.message, 'danger');
} }
function sendData() {
if (socket && socket.readyState === WebSocket.OPEN && rdpclient) {
const data = rdpclient.getOutputData();
if (data && data.length > 0) {
socket.send(data);
}
}
}
} }
function disconnect() { function disconnect() {
if (rdp) { if (socket) {
rdp.disconnect(); socket.close();
rdp = null; socket = null;
}
if (rdpclient) {
rdpclient = null;
} }
connected = false; connected = false;
document.getElementById('connectBtn').disabled = false; document.getElementById('connectBtn').disabled = false;
document.getElementById('disconnectBtn').disabled = true; document.getElementById('disconnectBtn').disabled = true;
// Reset UI to initial state // Reset UI to initial state
document.getElementById('mstsc_status').style.display = 'block'; document.getElementById('rdp_status').style.display = 'block';
document.getElementById('mstsc_loading').style.display = 'none'; document.getElementById('rdp_loading').style.display = 'none';
document.getElementById('cancelConnectBtn').style.display = 'none'; document.getElementById('cancelConnectBtn').style.display = 'none';
setTimeout(() => { setTimeout(() => {
location.reload(); location.reload();
...@@ -334,16 +385,19 @@ function disconnect() { ...@@ -334,16 +385,19 @@ function disconnect() {
} }
function cancelConnect() { function cancelConnect() {
if (rdp) { if (socket) {
rdp.disconnect(); socket.close();
rdp = null; socket = null;
}
if (rdpclient) {
rdpclient = null;
} }
connected = false; connected = false;
document.getElementById('connectBtn').disabled = false; document.getElementById('connectBtn').disabled = false;
document.getElementById('disconnectBtn').disabled = true; document.getElementById('disconnectBtn').disabled = true;
// Reset UI to initial state // Reset UI to initial state
document.getElementById('mstsc_status').style.display = 'block'; document.getElementById('rdp_status').style.display = 'block';
document.getElementById('mstsc_loading').style.display = 'none'; document.getElementById('rdp_loading').style.display = 'none';
document.getElementById('cancelConnectBtn').style.display = 'none'; document.getElementById('cancelConnectBtn').style.display = 'none';
showNotification('RDP connection cancelled', 'warning'); showNotification('RDP connection cancelled', 'warning');
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment