diff --git a/src/xpdev/objects.mk b/src/xpdev/objects.mk
index 2636dbb2ff8681a3fcc82509079a6e276ff1384b..7f46382958b6966fc553cf927153119c7af63a3e 100644
--- a/src/xpdev/objects.mk
+++ b/src/xpdev/objects.mk
@@ -17,6 +17,7 @@ OBJS	= \
 	$(OBJODIR)$(DIRSEP)link_list$(OFILE) \
 	$(OBJODIR)$(DIRSEP)netwrap$(OFILE) \
 	$(OBJODIR)$(DIRSEP)sockwrap$(OFILE) \
+	$(OBJODIR)$(DIRSEP)semfile$(OFILE) \
 	$(OBJODIR)$(DIRSEP)str_list$(OFILE) \
 	$(OBJODIR)$(DIRSEP)strwrap$(OFILE) \
 	$(OBJODIR)$(DIRSEP)xpbeep$(OFILE) \
@@ -36,6 +37,7 @@ MTOBJS	= \
 	$(MTOBJODIR)$(DIRSEP)semwrap$(OFILE) \
 	$(MTOBJODIR)$(DIRSEP)netwrap$(OFILE) \
 	$(MTOBJODIR)$(DIRSEP)sockwrap$(OFILE) \
+	$(MTOBJODIR)$(DIRSEP)semfile$(OFILE) \
 	$(MTOBJODIR)$(DIRSEP)str_list$(OFILE) \
 	$(MTOBJODIR)$(DIRSEP)strwrap$(OFILE) \
 	$(MTOBJODIR)$(DIRSEP)threadwrap$(OFILE) \
diff --git a/src/xpdev/semfile.c b/src/xpdev/semfile.c
new file mode 100644
index 0000000000000000000000000000000000000000..9e12cd894ffd6bbb41856cc1eb33221a815642a0
--- /dev/null
+++ b/src/xpdev/semfile.c
@@ -0,0 +1,140 @@
+/* semfile.c */
+
+/* $Id$ */
+
+/****************************************************************************
+ * @format.tab-size 4		(Plain Text/Source Code File Header)			*
+ * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
+ *																			*
+ * Copyright 2006 Rob Swindell - http://www.synchro.net/copyright.html		*
+ *																			*
+ * This program is free software; you can redistribute it and/or			*
+ * modify it under the terms of the GNU General Public License				*
+ * as published by the Free Software Foundation; either version 2			*
+ * of the License, or (at your option) any later version.					*
+ * See the GNU General Public License for more details: gpl.txt or			*
+ * http://www.fsf.org/copyleft/gpl.html										*
+ *																			*
+ * Anonymous FTP access to the most recent released source is available at	*
+ * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net	*
+ *																			*
+ * Anonymous CVS access to the development source and modification history	*
+ * is available at cvs.synchro.net:/cvsroot/sbbs, example:					*
+ * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login			*
+ *     (just hit return, no password is necessary)							*
+ * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src		*
+ *																			*
+ * For Synchronet coding style and modification guidelines, see				*
+ * http://www.synchro.net/source.html										*
+ *																			*
+ * You are encouraged to submit any modifications (preferably in Unix diff	*
+ * format) via e-mail to mods@synchro.net									*
+ *																			*
+ * Note: If this box doesn't appear square, then you need to fix your tabs.	*
+ ****************************************************************************/
+
+#include "semfile.h"
+#include "filewrap.h"
+#include "dirwrap.h"
+#include "genwrap.h"
+
+#if !defined(NO_SOCKET_SUPPORT)
+	#include "sockwrap.h"
+#endif
+
+/****************************************************************************/
+/* This function compares a single semaphore file's							*/
+/* date/time stamp (if the file exists) against the passed time stamp (t)	*/
+/* updating the time stamp to the latest dated semaphore file and returning	*/
+/* TRUE if any where newer than the initial value.							*/
+/****************************************************************************/
+BOOL DLLCALL semfile_check(time_t* t, const char* fname)
+{
+	time_t	ft;
+
+	if(*t==0)	/* uninitialized */
+		*t=time(NULL);
+
+	if((ft=fdate(fname))==-1 || ft<=*t)
+		return(FALSE);
+
+	*t=ft;
+	return(TRUE);
+}
+
+/****************************************************************************/
+/* This function goes through a list of semaphore files, comparing the file	*/
+/* date/time stamp (if the file exists) against the passed time stamp (t)	*/
+/* updating the time stamp to the latest dated semaphore file and returning	*/
+/* a pointer to the filename if any where newer than the initial timestamp.	*/
+/****************************************************************************/
+char* DLLCALL semfile_list_check(time_t* t, str_list_t filelist)
+{
+	char*	signaled=NULL;
+	size_t		i;
+
+	for(i=0;filelist[i]!=NULL;i++)
+		if(semfile_check(t, filelist[i]))
+			signaled = filelist[i];
+
+	return(signaled);
+}
+
+str_list_t DLLCALL semfile_list_init(const char* parent, 
+							   const char* action, const char* service)
+{
+	char	path[MAX_PATH+1];
+	char	hostname[128];
+	char*	p;
+	str_list_t	list;
+
+	if((list=strListInit())==NULL)
+		return(NULL);
+	SAFEPRINTF2(path,"%s%s",parent,action);
+	strListPush(&list,path);
+	SAFEPRINTF3(path,"%s%s.%s",parent,action,service);
+	strListPush(&list,path);
+	if(gethostname(hostname,sizeof(hostname))==0) {
+		SAFEPRINTF3(path,"%s%s.%s",parent,action,hostname);
+		strListPush(&list,path);
+		SAFEPRINTF4(path,"%s%s.%s.%s",parent,action,hostname,service);
+		strListPush(&list,path);
+		if((p=strchr(hostname,'.'))!=NULL) {
+			*p=0;
+			SAFEPRINTF3(path,"%s%s.%s",parent,action,hostname);
+			strListPush(&list,path);
+			SAFEPRINTF4(path,"%s%s.%s.%s",parent,action,hostname,service);
+			strListPush(&list,path);
+		}
+	}
+
+	return(list);
+}
+
+void DLLCALL semfile_list_add(str_list_t* filelist, const char* path)
+{
+	strListPush(filelist, path);
+}
+
+void DLLCALL semfile_list_free(str_list_t* filelist)
+{
+	strListFree(filelist);
+}
+
+BOOL DLLCALL semfile_signal(const char* fname, const char* text)
+{
+	int file;
+#if !defined(NO_SOCKET_SUPPORT)
+	char hostname[128];
+
+	if(text==NULL && gethostname(hostname,sizeof(hostname))==0)
+		text=hostname;
+#endif
+	if((file=open(fname,O_CREAT|O_WRONLY))<0)	/* use sopen instead? */
+		return(FALSE);
+	if(text!=NULL)
+		write(file,text,strlen(text));
+	/* use utime() for force the time-stamp to that of the local system? */
+	close(file);
+	return(TRUE);
+}
diff --git a/src/xpdev/semfile.h b/src/xpdev/semfile.h
new file mode 100644
index 0000000000000000000000000000000000000000..ee698517a914eae104793d5dae6d5637926e4687
--- /dev/null
+++ b/src/xpdev/semfile.h
@@ -0,0 +1,63 @@
+/* semfile.h */
+
+/* Semaphore file functions */
+
+/* $Id$ */
+
+/****************************************************************************
+ * @format.tab-size 4		(Plain Text/Source Code File Header)			*
+ * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
+ *																			*
+ * Copyright 2006 Rob Swindell - http://www.synchro.net/copyright.html		*
+ *																			*
+ * This library is free software; you can redistribute it and/or			*
+ * modify it under the terms of the GNU Lesser General Public License		*
+ * as published by the Free Software Foundation; either version 2			*
+ * of the License, or (at your option) any later version.					*
+ * See the GNU Lesser General Public License for more details: lgpl.txt or	*
+ * http://www.fsf.org/copyleft/lesser.html									*
+ *																			*
+ * Anonymous FTP access to the most recent released source is available at	*
+ * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net	*
+ *																			*
+ * Anonymous CVS access to the development source and modification history	*
+ * is available at cvs.synchro.net:/cvsroot/sbbs, example:					*
+ * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login			*
+ *     (just hit return, no password is necessary)							*
+ * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src		*
+ *																			*
+ * For Synchronet coding style and modification guidelines, see				*
+ * http://www.synchro.net/source.html										*
+ *																			*
+ * You are encouraged to submit any modifications (preferably in Unix diff	*
+ * format) via e-mail to mods@synchro.net									*
+ *																			*
+ * Note: If this box doesn't appear square, then you need to fix your tabs.	*
+ ****************************************************************************/
+
+#ifndef _SEMFILE_H
+#define _SEMFILE_H
+
+#include <time.h>		/* time_t */
+#include "str_list.h"	/* string list functions and types */
+#include "wrapdll.h"	/* DLLEXPORT and DLLCALL */
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/* semfile.c */
+DLLEXPORT BOOL		DLLCALL semfile_signal(const char* fname, const char* text);
+DLLEXPORT BOOL		DLLCALL semfile_check(time_t* t, const char* fname);
+DLLEXPORT char*		DLLCALL semfile_list_check(time_t* t, str_list_t filelist);
+DLLEXPORT str_list_t	
+					DLLCALL semfile_list_init(const char* parent, const char* action
+												,const char* service);
+DLLEXPORT void		DLLCALL semfile_list_add(str_list_t* filelist, const char* fname);
+DLLEXPORT void		DLLCALL semfile_list_free(str_list_t* filelist);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif	/* Don't add anything after this line */
diff --git a/src/xpdev/xpdev.dsp b/src/xpdev/xpdev.dsp
index 25fc48125df79a8aca0af12d67dfd7592abcef41..7448b0080a5352b0ceed6d0fba6d5dd6a07bde1d 100644
--- a/src/xpdev/xpdev.dsp
+++ b/src/xpdev/xpdev.dsp
@@ -114,6 +114,10 @@ SOURCE=.\netwrap.c
 # End Source File
 # Begin Source File
 
+SOURCE=.\semfile.c
+# End Source File
+# Begin Source File
+
 SOURCE=.\sockwrap.c
 # End Source File
 # Begin Source File
diff --git a/src/xpdev/xpdev_mt.dsp b/src/xpdev/xpdev_mt.dsp
index 013150cb0526252accc4e135466f5f452305bb41..e9eb281ff1f5a9cf03f7022d6684711b21c85594 100644
--- a/src/xpdev/xpdev_mt.dsp
+++ b/src/xpdev/xpdev_mt.dsp
@@ -114,6 +114,10 @@ SOURCE=.\netwrap.c
 # End Source File
 # Begin Source File
 
+SOURCE=.\semfile.c
+# End Source File
+# Begin Source File
+
 SOURCE=.\semwrap.c
 # End Source File
 # Begin Source File