diff --git a/src/build/Common.gmake b/src/build/Common.gmake
index adececc56a61ba2ddee4b17c8cbc26d5a5fb6a20..fa07173eafdc6ff4486530a3f51ad8040745b042 100644
--- a/src/build/Common.gmake
+++ b/src/build/Common.gmake
@@ -249,6 +249,9 @@ ifeq ($(machine_uname),mac68k)
 endif
 ifeq ($(machine_uname),)
  machine	:=	$(os)
+endif
+ifeq ($(os),emscripten)
+ machine	:=	webassembly
 else
  machine	:=	$(os).$(machine_uname)
  CFLAGS +=      -DUNAME_ARCHITECTURE_DESC=$(machine_uname)
@@ -382,9 +385,13 @@ else
       ifeq ($(os),win32) # Windows
        CFLAGS		+= -U__STRICT_ANSI__ -D_WIN32 -D_WIN32_WINNT=0x0501 -DWINVER=0x0501 -D_WIN32_IE=0x0500
        MT_CFLAGS	+= -D_WIN32
-      else           # Linux / Other UNIX
-       XP_SEM :=    1
-       MT_CFLAGS    += -DUSE_XP_SEMAPHORES
+      else
+       ifeq ($(os),emscripten)
+        CFLAGS += -D_BSD_SOURCE -D__STDC_NO_ATOMICS__
+       else           # Linux / Other UNIX
+        XP_SEM :=    1
+        MT_CFLAGS    += -DUSE_XP_SEMAPHORES
+       endif
       endif
      endif
     endif
diff --git a/src/syncterm/COMPILING b/src/syncterm/COMPILING
index 581b7bf8c15479a115439e93b1c90c27eef5f12a..8c186a6113263321d8db5be0c38f1fc9567932fa 100644
--- a/src/syncterm/COMPILING
+++ b/src/syncterm/COMPILING
@@ -48,5 +48,8 @@ hdiutil convert ~/Desktop/SyncTERM.dmg -format UDRO -o /Volumes/Synchronet/sbbs/
 Release builds for Win32 using MinGW32 use the following command line:
 gmake CC=mingw32-gcc VERBOSE=please AR=mingw32-ar AS=mingw32-as RANLIB=mingw32-ranlib RELEASE=1 CXX=mingw32-g++ WINDRES=mingw32-windres
 
+Release builds for Emscripten use the following command line:
+gmake CC=emcc VERBOSE=please AR=emar RANLIB=emranlib RELEASE=1 CXX=emc++ os=emscripten
+
 Release builds of jsdoor (not related at all)
 gmake jsdoor NO_LD_RUN_PATH=dumbass CC=mingw32-gcc VERBOSE=please AR=mingw32-ar AS=mingw32-as RANLIB=mingw32-ranlib RELEASE=1 CXX=mingw32-g++ WINDRES=mingw32-windres JSLIBDIR=../../3rdp/win32.release/mozjs/bin/ JSINCLUDE=../../3rdp/win32.release/mozjs/include/ JSLIB=mozjs
diff --git a/src/xpdev/conwrap.c b/src/xpdev/conwrap.c
index 3b0edd90af9ca19bbff064d19d953aa0b73e9768..470b7b4f7cba549d1783433af5661fcf14329f35 100644
--- a/src/xpdev/conwrap.c
+++ b/src/xpdev/conwrap.c
@@ -65,6 +65,7 @@ void _termios_reset(void)
 #if defined(__BORLANDC__)
         #pragma argsused
 #endif
+#ifndef __EMSCRIPTEN_major__
 void _sighandler_stop(int sig)
 {
     /* clean up the terminal */
@@ -73,6 +74,7 @@ void _sighandler_stop(int sig)
     /* ... and stop */
 	kill(getpid(), SIGSTOP);
 }
+#endif
 #if defined(__BORLANDC__)
         #pragma argsused
 #endif
@@ -103,7 +105,9 @@ void _termios_setup(void)
     atexit(_termios_reset);
 
     /* install the Ctrl-Z handler */
+#ifndef __EMSCRIPTEN_major__
     signal(SIGTSTP, _sighandler_stop);
+#endif
     signal(SIGCONT, _sighandler_cont);
 }
 
diff --git a/src/xpdev/dat_file.c b/src/xpdev/dat_file.c
index 37b4fa831312832e3b048f71442cd753bddd758e..c098a9f650d49fbc490f2be3ae50958576ae1cbb 100644
--- a/src/xpdev/dat_file.c
+++ b/src/xpdev/dat_file.c
@@ -23,7 +23,7 @@
 #include "genwrap.h"	/* lastchar */
 #include "filewrap.h"	/* chsize */
 #include <stdlib.h>		/* malloc */
-#include <string.h>		/* strdup */
+#include "strwrap.h"		/* strdup */
 
 /***********************************/
 /* CSV (Comma Separated Value) API */
@@ -206,6 +206,10 @@ str_list_t dataCreateList(const str_list_t records[], const str_list_t columns,
 BOOL dataWriteFile(FILE* fp, const str_list_t records[], const str_list_t columns, const char* separator
 				   ,dataLineCreator_t lineCreator)
 {
+#ifdef __EMSCRIPTEN_major__
+	fprintf(stderr, "%s not implemented.\n", __func__);
+	return FALSE;
+#else
 	size_t		count,total;
 	str_list_t	list;
 
@@ -222,6 +226,7 @@ BOOL dataWriteFile(FILE* fp, const str_list_t records[], const str_list_t column
 	strListFree(&list);
 
 	return(count == total);
+#endif
 }
 
 str_list_t* dataParseList(const str_list_t records, str_list_t* columns, dataLineParser_t lineParser)
diff --git a/src/xpdev/datewrap.c b/src/xpdev/datewrap.c
index 3c2e9168e366bacd34537a0a2f555296bd6307c7..7f3f228f549589383ae4db44b76f17ce023abc09 100644
--- a/src/xpdev/datewrap.c
+++ b/src/xpdev/datewrap.c
@@ -157,7 +157,7 @@ void gettime(struct time* nyt)
 
 #endif	/* !Borland */
 
-#if !defined(__unix__)
+#if (!defined(__unix__)) || defined(__EMSCRIPTEN_major__)
 
 /****************************************************************************/
 /* Win32 implementations of the recursive (thread-safe) versions of std C	*/
diff --git a/src/xpdev/datewrap.h b/src/xpdev/datewrap.h
index c57cd9447f357a5cb0ff3cae2f564b353970bebd..e17b2afd0fb8659f1ecd53c02d111815d1412a79 100644
--- a/src/xpdev/datewrap.h
+++ b/src/xpdev/datewrap.h
@@ -44,7 +44,7 @@ DLLEXPORT struct tm*	localtime32(const time32_t* t, struct tm* tm);
 /* Win32 implementations of recursive (thread-safe) std C time functions on Unix */
 /*********************************************************************************/
 
-#if !defined(__unix__)	
+#if (!defined(__unix__)) || defined(__EMSCRIPTEN_major__)
 
 	#include <time.h>		/* time_t, etc. */
 
@@ -60,6 +60,10 @@ DLLEXPORT struct tm*	localtime32(const time32_t* t, struct tm* tm);
 	#define timegm _mkgmtime
 #endif
 
+#if defined(__EMSCRIPTEN_major__)
+	#define timegm	mktime
+#endif
+
 /***********************************/
 /* Borland DOS date/time functions */
 /***********************************/
diff --git a/src/xpdev/dirwrap.c b/src/xpdev/dirwrap.c
index 5f1626eb0d8d171c83c255fe32c3fb8a009fc487..cc8cb2ca893029cae1ed666fa2eb8657a873159b 100644
--- a/src/xpdev/dirwrap.c
+++ b/src/xpdev/dirwrap.c
@@ -814,7 +814,9 @@ int delfiles(const char *inpath, const char *spec, size_t keep)
 				errors++;
 			continue;
 		}
+#ifndef __EMSCRIPTEN_major__
 		(void)CHMOD(fpath, S_IWRITE);	/* In case it's been marked RDONLY */
+#endif
 		if(remove(fpath)==0)
 			files++;
 		else
@@ -1218,6 +1220,10 @@ int mkpath(const char* path)
 #if !defined _WIN32
 BOOL CopyFile(const char* src, const char* dest, BOOL failIfExists)
 {
+#ifdef __EMSCRIPTEN_major__
+	fprintf(stderr, "%s not implemented\n", __func__);
+	return FALSE;
+#else
 	uint8_t	buf[256 * 1024];
 	FILE*	in;
 	FILE*	out;
@@ -1249,5 +1255,6 @@ BOOL CopyFile(const char* src, const char* dest, BOOL failIfExists)
 	setfdate(dest,ftime);
 
 	return success;
+#endif
 }
 #endif
diff --git a/src/xpdev/filewrap.c b/src/xpdev/filewrap.c
index 62c1670a59dd0ae032765205d7bcba50826845ba..82c71d2f9ffae5ba408a739b3272d46bd1bd8048 100644
--- a/src/xpdev/filewrap.c
+++ b/src/xpdev/filewrap.c
@@ -194,7 +194,11 @@ int unlock(int fd, off_t pos, off_t len)
 int sopen(const char *fn, int sh_access, int share, ...)
 {
 	int fd;
+#ifdef S_IREAD
 	int pmode=S_IREAD;
+#else
+	int pmode=0;
+#endif
 #ifndef F_SANEWRLCKNO
 	int	flock_op=LOCK_NB;	/* non-blocking */
 #endif
@@ -367,6 +371,10 @@ long getdelim(char **linep, size_t *linecapp, int delimiter, FILE *stream)
 #ifdef __unix__
 FILE *_fsopen(const char *pszFilename, const char *pszMode, int shmode)
 {
+#ifdef __EMSCRIPTEN_major__
+	fprintf(stderr, "%s not implemented\n", __func__);
+	return NULL;
+#else
 	int file;
 	int Mode=0;
 	const char *p;
@@ -423,5 +431,6 @@ FILE *_fsopen(const char *pszFilename, const char *pszMode, int shmode)
 	if(file==-1)
 		return(NULL);
 	return(fdopen(file,pszMode));
+#endif
 }
 #endif
diff --git a/src/xpdev/genwrap.c b/src/xpdev/genwrap.c
index 768d7a1830845185793bf8797e474ec39c12f841..a1969854a5472ea523d317a84d0ffc30ecc2fc7b 100644
--- a/src/xpdev/genwrap.c
+++ b/src/xpdev/genwrap.c
@@ -29,6 +29,7 @@
 #include <limits.h>		/* CHAR_BIT */
 #include <math.h>		/* fmod */
 
+#include "strwrap.h"		/* strdup */
 #include "ini_file.h"
 
 #if defined(__unix__)
@@ -982,6 +983,10 @@ uint64_t xp_timer64(void)
 /* Returns TRUE if specified process is running */
 BOOL check_pid(pid_t pid)
 {
+#ifdef __EMSCRIPTEN_major__
+	fprintf(stderr, "%s not implemented", __func__);
+	return FALSE;
+#else
 #if defined(__unix__)
 	return(kill(pid,0)==0);
 #elif defined(_WIN32)
@@ -998,11 +1003,16 @@ BOOL check_pid(pid_t pid)
 #else
 	return FALSE;	/* Need check_pid() definition! */
 #endif
+#endif
 }
 
 /* Terminate (unconditionally) the specified process */
 BOOL terminate_pid(pid_t pid)
 {
+#ifdef __EMSCRIPTEN_major__
+	fprintf(stderr, "%s not implemented", __func__);
+	return FALSE;
+#else
 #if defined(__unix__)
 	return(kill(pid,SIGKILL)==0);
 #elif defined(_WIN32)
@@ -1018,6 +1028,7 @@ BOOL terminate_pid(pid_t pid)
 #else
 	return FALSE;	/* Need check_pid() definition! */
 #endif
+#endif
 }
 
 /****************************************************************************/
@@ -1031,7 +1042,7 @@ char* safe_strerror(int errnum, char *buf, size_t buflen)
 
 #if defined(_MSC_VER)
 	strerror_s(buf, buflen, errnum);
-#elif defined(_WIN32)
+#elif defined(_WIN32) || defined(__EMSCRIPTEN_major__)
 	strncpy(buf, strerror(errnum), buflen);
 	buf[buflen - 1] = 0;
 #elif defined(_GNU_SOURCE)
diff --git a/src/xpdev/genwrap.h b/src/xpdev/genwrap.h
index 17d0a80fb63892f970b1be470cf9967567919ddc..8c238ec656ddfbea9837d0e4d7c7860cc01dee34 100644
--- a/src/xpdev/genwrap.h
+++ b/src/xpdev/genwrap.h
@@ -30,7 +30,6 @@
 
 #if defined(__unix__)
 	#include <sched.h>		/* sched_yield */
-	#include <time.h>	/* clock_t */
 	#include <sys/time.h>	/* struct timeval */
 	#include <strings.h>	/* strcasecmp() */
 	#include <unistd.h>		/* usleep */
@@ -202,6 +201,8 @@ extern "C" {
 	#define ARCHITECTURE_DESC "ppc"
 #elif defined(_M_IA64) || defined(__ia64__)
 	#define ARCHITECTURE_DESC "ia64"
+#elif defined(__EMSCRIPTEN_major__)
+	#define ARCHITECTURE_DESC "wasm"
 #else
 	#ifdef UNAME_ARCHITECTURE_DESC
 		#define ARCHITECTURE_DESC UNAME_ARCHITECTURE_DESC
diff --git a/src/xpdev/strwrap.c b/src/xpdev/strwrap.c
index 00fff9a4c5612bca9db38e3c70c3a9f6b0d81124..f39df09641dedb41020a3996fc9951736f9988db 100644
--- a/src/xpdev/strwrap.c
+++ b/src/xpdev/strwrap.c
@@ -75,3 +75,39 @@ strndup(const char *str, size_t maxlen)
 	return copy;
 }
 #endif
+
+#if defined(__EMSCRIPTEN_major__)
+char *
+strdup(const char *str)
+{
+	if (str == NULL)
+		return NULL;
+	char *ret = malloc(strlen(str) + 1);
+	if (ret != NULL)
+		strcpy(ret, str);
+	return ret;
+}
+
+char *
+strtok_r(char *str, const char *delim, char **saveptr)
+{
+	char *ret;
+	char *end;
+
+	if (str == NULL)
+		str = *saveptr;
+	if (str == NULL)
+		return NULL;
+	end = strchr(str, '\0');
+	ret = strtok(str, delim);
+	if (ret == NULL) {
+		*saveptr = NULL;
+	}
+	else {
+		*saveptr = strchr(ret, '\0') + 1;
+		if (*saveptr > end)
+			*saveptr = NULL;
+	}
+	return ret;
+}
+#endif
diff --git a/src/xpdev/strwrap.h b/src/xpdev/strwrap.h
index 482fa1f53ba522e5a23485a87ef00b6bd5a0d04d..97d77bc82ef05e71618c39a771aeda772e8c8519 100644
--- a/src/xpdev/strwrap.h
+++ b/src/xpdev/strwrap.h
@@ -33,4 +33,15 @@ size_t strnlen(const char *s, size_t maxlen);
 #endif
 #endif
 
+#if defined(__cplusplus)
+extern "C" {
+#endif
+#if defined(__EMSCRIPTEN_major__)
+char * strdup(const char *str);
+char * strtok_r(char *str, const char *delim, char **saveptr);
+#endif
+#if defined(__cplusplus)
+}
+#endif
+
 #endif
diff --git a/src/xpdev/wraptest.c b/src/xpdev/wraptest.c
index cf92bf24d112c9e3d980f76114edba10b59e3e05..20bacf82e3f6bc53a784d5e0942b21af9085cfd4 100644
--- a/src/xpdev/wraptest.c
+++ b/src/xpdev/wraptest.c
@@ -56,7 +56,7 @@ int main()
 	/* Show platform details */
 	DESCRIBE_COMPILER(compiler);
 	printf("%-15s: %s\n","Platform",PLATFORM_DESC);
-	printf("%-15s: %s\n","Version",os_version(str));
+	printf("%-15s: %s\n","Version",os_version(str, sizeof(str)));
 	printf("%-15s: %s\n","Compiler"	,compiler);
 	printf("%-15s: %ld\n","Random Number",xp_random(1000));
 
diff --git a/src/xpdev/xpbeep.c b/src/xpdev/xpbeep.c
index 4e8e6ce53cf8d15e1489e3cbcf86e55a4dd40c7d..8d9b13c899e58a98b4cdc3360f0a5804983ef189 100644
--- a/src/xpdev/xpbeep.c
+++ b/src/xpdev/xpbeep.c
@@ -13,37 +13,39 @@
 #elif defined(__unix__)
 	#include <fcntl.h>
 	#include <sys/ioctl.h>
-	#if SOUNDCARD_H_IN==1
-		#include <sys/soundcard.h>
-	#elif SOUNDCARD_H_IN==2
-		#include <soundcard.h>
-	#elif SOUNDCARD_H_IN==3
-		#include <linux/soundcard.h>
-	#else
-		#ifndef USE_ALSA_SOUND
-			#warning Cannot find soundcard.h
+	#ifndef __EMSCRIPTEN_major__
+		#if SOUNDCARD_H_IN==1
+			#include <sys/soundcard.h>
+		#elif SOUNDCARD_H_IN==2
+			#include <soundcard.h>
+		#elif SOUNDCARD_H_IN==3
+			#include <linux/soundcard.h>
+		#else
+			#ifndef USE_ALSA_SOUND
+				#warning Cannot find soundcard.h
+			#endif
 		#endif
-	#endif
-	#ifdef USE_ALSA_SOUND
-		#include <dlfcn.h>
-		#include <alsa/asoundlib.h>
-	#endif
-	/* KIOCSOUND */
-	#if defined(__FreeBSD__)
-		#include <sys/kbio.h>
-	#elif defined(__linux__)
-		#include <sys/kd.h>	
-	#elif defined(__solaris__)
-		#include <sys/kbio.h>
-		#include <sys/kbd.h>
-	#endif
-	#if (defined(__OpenBSD__) || defined(__NetBSD__)) && defined(HAS_MACHINE_SPKR_H)
-		#include <machine/spkr.h>
-	#elif defined(__FreeBSD__)
-		#if defined(HAS_DEV_SPEAKER_SPEAKER_H)
-			#include <dev/speaker/speaker.h>
-		#elif defined(HAS_MACHINE_SPEAKER_H)
-			#include <machine/speaker.h>
+		#ifdef USE_ALSA_SOUND
+			#include <dlfcn.h>
+			#include <alsa/asoundlib.h>
+		#endif
+		/* KIOCSOUND */
+		#if defined(__FreeBSD__)
+			#include <sys/kbio.h>
+		#elif defined(__linux__)
+			#include <sys/kd.h>
+		#elif defined(__solaris__)
+			#include <sys/kbio.h>
+			#include <sys/kbd.h>
+		#endif
+		#if (defined(__OpenBSD__) || defined(__NetBSD__)) && defined(HAS_MACHINE_SPKR_H)
+			#include <machine/spkr.h>
+		#elif defined(__FreeBSD__)
+			#if defined(HAS_DEV_SPEAKER_SPEAKER_H)
+				#include <dev/speaker/speaker.h>
+			#elif defined(HAS_MACHINE_SPEAKER_H)
+				#include <machine/speaker.h>
+			#endif
 		#endif
 	#endif
 #endif
@@ -1196,7 +1198,7 @@ void unix_beep(int freq, int dur)
 	}
 #endif
 
-#if !defined(__GNU__) && !defined(__QNX__) && !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(__APPLE__) && !defined(__CYGWIN__) && !defined(__HAIKU__)
+#if !defined(__GNU__) && !defined(__QNX__) && !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(__APPLE__) && !defined(__CYGWIN__) && !defined(__HAIKU__) && !defined(__EMSCRIPTEN_major__)
 	if(console_fd == -1) 
   		console_fd = open("/dev/console", O_NOCTTY);