diff --git a/src/xpdev/ini_file.c b/src/xpdev/ini_file.c
new file mode 100644
index 0000000000000000000000000000000000000000..ea13874f617a4693edb3c6f82b54fbdd495de920
--- /dev/null
+++ b/src/xpdev/ini_file.c
@@ -0,0 +1,226 @@
+/* ini_file.c */
+
+/* Functions to parse ini files */
+
+/* $Id$ */
+
+/****************************************************************************
+ * @format.tab-size 4		(Plain Text/Source Code File Header)			*
+ * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
+ *																			*
+ * Copyright 2002 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.	*
+ ****************************************************************************/
+
+#include <stdlib.h>		/* strtol */
+#include "sockwrap.h"	/* inet_addr */
+#include "ini_file.h"
+
+#define MAX_LINE_LEN	256		/* includes '\0' */
+#define MAX_VALUE_LEN	128		/* includes '\0' */
+
+/****************************************************************************/
+/* Truncates white-space chars off end of 'str'								*/
+/****************************************************************************/
+static void truncsp(char *str)
+{
+	uint c;
+
+	c=strlen(str);
+	while(c && (uchar)str[c-1]<=SP) c--;
+	str[c]=0;
+}
+
+static BOOL find_section(FILE* fp, const char* section)
+{
+	char*	p;
+	char*	tp;
+	char	str[MAX_LINE_LEN];
+
+	rewind(fp);
+
+	while(!feof(fp)) {
+		if(fgets(str,sizeof(str)-1,fp)==NULL)
+			break;
+		p=str;
+		while(*p && *p<=' ') p++;
+		if(*p!='[')
+			continue;
+		p++;
+		tp=strchr(p,']');
+		if(tp==NULL)
+			continue;
+		*tp=0;
+		return(TRUE);
+	}
+	return(FALSE);
+}
+
+static char* get_value(FILE* fp, const char* section, const char* key)
+{
+	char*	p;
+	char*	tp;
+	char	str[MAX_LINE_LEN];
+	static char value[MAX_VALUE_LEN];
+
+	if(!find_section(fp,section))
+		return(NULL);
+
+	while(!feof(fp)) {
+		if(fgets(str,sizeof(str)-1,fp)==NULL)
+			break;
+		p=str;
+		while(*p && *p<=' ') p++;
+		if(*p==';')
+			continue;
+		if(*p=='[')
+			break;
+		tp=strchr(p,'=');
+		if(tp==NULL)
+			continue;
+		*tp=0;
+		truncsp(p);
+		if(stricmp(p,key)!=0)
+			continue;
+		/* key found */
+		p=tp+1;
+		while(*p && *p<=' ') p++;
+		truncsp(p);
+		SAFECOPY(value,p);
+		return(value);
+	}
+
+	return(NULL);
+}
+
+char* DLLCALL
+iniReadString(FILE* fp, const char* section, const char* key, const char* deflt)
+{
+	char* value;
+
+	if((value=get_value(fp,section,key))==NULL)
+		return((char*)deflt);
+
+	return(value);
+}
+
+long DLLCALL
+iniReadInteger(FILE* fp, const char* section, const char* key, long deflt)
+{
+	char* value;
+
+	if((value=get_value(fp,section,key))==NULL)
+		return(deflt);
+
+	return(strtol(value,NULL,0));
+}
+
+ushort DLLCALL
+iniReadShortInt(FILE* fp, const char* section, const char* key, ushort deflt)
+{
+	return((ushort)iniReadInteger(fp, section, key, deflt));
+}
+
+ulong DLLCALL
+iniReadIpAddress(FILE* fp, const char* section, const char* key, ulong deflt)
+{
+	char* value;
+
+	if((value=get_value(fp,section,key))==NULL)
+		return(deflt);
+
+	if(strchr(value,'.')==NULL)
+		return(strtol(value,NULL,0));
+
+	return(inet_addr(value));
+}
+
+double DLLCALL
+iniReadFloat(FILE* fp, const char* section, const char* key, double deflt)
+{
+	char* value;
+
+	if((value=get_value(fp,section,key))==NULL)
+		return(deflt);
+
+	return(atof(value));
+}
+
+BOOL DLLCALL 
+iniReadBool(FILE* fp, const char* section, const char* key, BOOL deflt)
+{
+	char* value;
+
+	if((value=get_value(fp,section,key))==NULL)
+		return(deflt);
+
+	if(!stricmp(value,"TRUE"))
+		return(TRUE);
+	if(!stricmp(value,"FALSE"))
+		return(FALSE);
+
+	return(strtol(value,NULL,0));
+}
+
+ulong DLLCALL
+iniReadBitField(FILE* fp, const char* section, const char* key, 
+						ini_bitdesc_t* bitdesc, ulong deflt)
+{
+	int		b,i;
+	char*	p;
+	char*	tp;
+	char*	value;
+	ulong	v=0;
+
+	if((value=get_value(fp,section,key))==NULL)
+		return(deflt);
+
+	if(isdigit(value[0]))
+		return(strtoul(value,NULL,0));
+
+	p=value;
+	for(b=0;*p && b<32;b++) {
+		tp=strchr(p,'|');
+		if(tp!=NULL)
+			*tp=0;
+		truncsp(p);
+
+		for(i=0;bitdesc[i].name;i++)
+			if(!stricmp(bitdesc[i].name,p))
+				break;
+
+		if(bitdesc[i].name)
+			v|=bitdesc[i].bit;
+
+		if(tp==NULL)
+			break;
+
+		p=tp+1;
+		while(*p && *p<=' ') p++;
+	}
+
+	return(v);
+}
diff --git a/src/xpdev/ini_file.h b/src/xpdev/ini_file.h
new file mode 100644
index 0000000000000000000000000000000000000000..4211120bb9f5ede437387eae371ff71086642b1a
--- /dev/null
+++ b/src/xpdev/ini_file.h
@@ -0,0 +1,82 @@
+/* ini_file.h */
+
+/* Functions to parse ini files */
+
+/* $Id$ */
+
+/****************************************************************************
+ * @format.tab-size 4		(Plain Text/Source Code File Header)			*
+ * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
+ *																			*
+ * Copyright 2002 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 _INI_FILE_H
+#define _INI_FILE_H
+
+#include "genwrap.h"
+#include "wrapdll.h"	/* DLLEXPORT and DLLCALL */
+
+typedef struct {
+	ulong		bit;
+	const char*	name;
+} ini_bitdesc_t;
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+//DLLEXPORT 
+char*		DLLCALL iniReadString	(FILE* fp, const char* section, const char* key, 
+											 const char* deflt);
+//DLLEXPORT 
+long		DLLCALL	iniReadInteger	(FILE* fp, const char* section, const char* key, 
+											 long deflt);
+
+//DLLEXPORT 
+ushort		DLLCALL	iniReadShortInt	(FILE* fp, const char* section, const char* key, 
+											 ushort deflt);
+
+//DLLEXPORT 
+ulong		DLLCALL	iniReadIpAddress	(FILE* fp, const char* section, const char* key, 
+											 ulong deflt);
+
+//DLLEXPORT 
+double	DLLCALL	iniReadFloat	(FILE* fp, const char* section, const char* key, 
+											 double deflt);
+//DLLEXPORT 
+BOOL		DLLCALL iniReadBool		(FILE* fp, const char* section, const char* key, 
+											 BOOL deflt);
+//DLLEXPORT 
+ulong		DLLCALL	iniReadBitField	(FILE* fp, const char* section, const char* key, 
+											 ini_bitdesc_t* bitdesc, ulong deflt);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif	/* Don't add anything after this line */