diff --git a/src/build/Common.gmake b/src/build/Common.gmake
index 47161877d60e67ffa489bcd00c7668521acf390d..4545d8e3b29ad973365fa35c3bb613c77d10ce71 100644
--- a/src/build/Common.gmake
+++ b/src/build/Common.gmake
@@ -535,6 +535,11 @@ $(MTOBJODIR)/%$(OFILE) : %.cpp $(BUILD_DEPENDS) | $(MTOBJODIR)
 	@echo $(COMPILE_MSG) $<
 	$(QUIET)$(CXX) -std=c++11 $(CFLAGS) $(CXXFLAGS) $(MT_CFLAGS) -o $@ -c $<
 
+# Implicit MT Obj-C Compile Rule
+$(MTOBJODIR)/%$(OFILE) : %.m $(BUILD_DEPENDS) | $(MTOBJODIR)
+	@echo $(COMPILE_MSG) $<
+	$(QUIET)$(CC) -ObjC $(CFLAGS) $(CCFLAGS) $(MT_CFLAGS) -o $@ -c $<
+
 depend:
 	$(QUIET)$(DELETE) $(OBJODIR)/.depend
 	$(QUIET)$(DELETE) $(MTOBJODIR)/.depend
diff --git a/src/syncterm/DarwinWrappers.h b/src/syncterm/DarwinWrappers.h
new file mode 100644
index 0000000000000000000000000000000000000000..3b7a350b58733d8a2d98c8c5e967a55150d74043
--- /dev/null
+++ b/src/syncterm/DarwinWrappers.h
@@ -0,0 +1,6 @@
+#ifndef DARWINWRAPPERS_H
+#define DARWINWRAPPERS_H
+
+extern char * get_OSX_filename(char *fn, int fnlen, int type, int shared);
+
+#endif
diff --git a/src/syncterm/DarwinWrappers.m b/src/syncterm/DarwinWrappers.m
new file mode 100644
index 0000000000000000000000000000000000000000..bb3fd125ee8c74929d25789d95a4586e919c5885
--- /dev/null
+++ b/src/syncterm/DarwinWrappers.m
@@ -0,0 +1,132 @@
+#include <stdbool.h>
+#include <string.h>
+#include "syncterm.h"
+#include "dirwrap.h"
+#undef BOOL
+
+#if 1 // TODO: Make this conditional on min version...
+#import <Foundation/Foundation.h>
+
+char *
+get_OSX_filename(char *fn, int fnlen, int type, int shared)
+{
+	NSSearchPathDomainMask domain = shared ? NSLocalDomainMask : NSUserDomainMask;
+	NSSearchPathDirectory path;
+	switch(type) {
+		case SYNCTERM_PATH_INI:
+			path = NSLibraryDirectory;
+			break;
+		case SYNCTERM_PATH_LIST:
+			path = NSLibraryDirectory;
+			break;
+		case SYNCTERM_DEFAULT_TRANSFER_PATH:
+			path = NSDownloadsDirectory;
+			break;
+		case SYNCTERM_PATH_CACHE:
+			path = NSCachesDirectory;
+			break;
+		case SYNCTERM_PATH_KEYS:
+			path = NSLibraryDirectory;
+			break;
+	}
+
+	NSError *error = nil;
+	NSURL *none = nil;
+	NSURL *result = [[NSFileManager defaultManager] URLForDirectory:path inDomain:domain appropriateForURL:none create:NO error:&error];
+	if (result == nil) {
+		strlcpy(fn, error.localizedDescription.UTF8String, fnlen);
+		return NULL;
+	}
+	strlcpy(fn, result.path.UTF8String, fnlen);
+	switch(type) {
+		case SYNCTERM_PATH_INI:
+			strlcat(fn, "/Preferences/SyncTERM/SyncTERM.ini", fnlen);
+			break;
+		case SYNCTERM_PATH_LIST:
+			strlcat(fn, "/Preferences/SyncTERM/SyncTERM.lst", fnlen);
+			break;
+		case SYNCTERM_DEFAULT_TRANSFER_PATH:
+			strlcat(fn, "/", fnlen);
+			break;
+		case SYNCTERM_PATH_CACHE:
+			strlcat(fn, "/SyncTERM/", fnlen);
+			break;
+		case SYNCTERM_PATH_KEYS:
+			strlcat(fn, "/Preferences/SyncTERM/SyncTERM.ssh", fnlen);
+			break;
+	}
+
+	return fn;
+}
+
+#else
+#include <CoreServices/CoreServices.h> // FSFindFolder() and friends
+
+char *
+get_OSX_filename(char *fn, int fnlen, int type, int shared)
+{
+	FSRef ref;
+	char *ret = fn;
+	if (fnlen > 0)
+		fn[0] = 0;
+
+        /* First, get the path */
+	switch (type) {
+		case SYNCTERM_PATH_INI:
+		case SYNCTERM_PATH_LIST:
+		case SYNCTERM_PATH_KEYS:
+			if (FSFindFolder(shared ? kLocalDomain : kUserDomain, kPreferencesFolderType, kCreateFolder,
+			    &ref) != noErr)
+				ret = NULL;
+			if (FSRefMakePath(&ref, (unsigned char *)fn, fnlen) != noErr)
+				ret = NULL;
+			backslash(fn);
+			strncat(fn, "SyncTERM", fnlen - strlen(fn) - 1);
+			backslash(fn);
+			if (!isdir(fn)) {
+				if (MKDIR(fn))
+					ret = NULL;
+			}
+			break;
+
+		case SYNCTERM_DEFAULT_TRANSFER_PATH:
+                        /* I'd love to use the "right" setting here, but don't know how */
+			if (FSFindFolder(shared ? kLocalDomain : kUserDomain, kDownloadsFolderType, kCreateFolder,
+			    &ref) != noErr)
+				ret = NULL;
+			if (FSRefMakePath(&ref, (unsigned char *)fn, fnlen) != noErr)
+				ret = NULL;
+			backslash(fn);
+			if (!isdir(fn)) {
+				if (MKDIR(fn))
+					ret = NULL;
+			}
+			break;
+		case SYNCTERM_PATH_CACHE:
+			if (FSFindFolder(shared ? kLocalDomain : kUserDomain, kCachedDataFolderType, kCreateFolder,
+			    &ref) != noErr)
+				ret = NULL;
+			if (FSRefMakePath(&ref, (unsigned char *)fn, fnlen) != noErr)
+				ret = NULL;
+			backslash(fn);
+			break;
+	}
+
+	switch (type) {
+		case SYNCTERM_PATH_INI:
+			strncat(fn, "SyncTERM.ini", fnlen - strlen(fn) - 1);
+			break;
+		case SYNCTERM_PATH_LIST:
+			strncat(fn, "SyncTERM.lst", fnlen - strlen(fn) - 1);
+			break;
+		case SYNCTERM_PATH_KEYS:
+			strncat(fn, "SyncTERM.ssh", fnlen - strlen(fn) - 1);
+			break;
+		case SYNCTERM_PATH_CACHE:
+			strncat(fn, "SyncTERM/", fnlen - strlen(fn) - 1);
+			break;
+	}
+	return ret;
+}
+
+#endif
diff --git a/src/syncterm/GNUmakefile b/src/syncterm/GNUmakefile
index 1494068dcabe55c6502e591de3813dc42ee8885a..538f93a47e6c6b13a0091d68683686fe356e5417 100644
--- a/src/syncterm/GNUmakefile
+++ b/src/syncterm/GNUmakefile
@@ -35,7 +35,8 @@ else
 endif
 
 ifeq ($(os),darwin)
- EXTRA_LIBS += -framework CoreServices
+ OBJS += $(MTOBJODIR)$(DIRSEP)DarwinWrappers$(OFILE)
+ EXTRA_LIBS += -framework Foundation
  STATIC_CRYPTLIB ?= 1
 endif
 
diff --git a/src/syncterm/syncterm.c b/src/syncterm/syncterm.c
index bd665bd09bef29c0b0e955cdd9a1717b57586f0a..532efa8bccc37299a8bfc78fea3e82a5a4cbe3c1 100644
--- a/src/syncterm/syncterm.c
+++ b/src/syncterm/syncterm.c
@@ -3,7 +3,7 @@
 /* $Id: syncterm.c,v 1.261 2020/06/27 00:04:50 deuce Exp $ */
 
 #if defined(__APPLE__) && defined(__MACH__)
- #include <CoreServices/CoreServices.h> // FSFindFolder() and friends
+ #include "DarwinWrappers.h"
 #endif
 
 #define NOCRYPT                         /* Stop windows.h from loading wincrypt.h */
@@ -973,67 +973,6 @@ parse_url(char *url, struct bbslist *bbs, int dflt_conn_type, int force_defaults
 
 #if defined(__APPLE__) && defined(__MACH__)
 
-static char *
-get_OSX_filename(char *fn, int fnlen, int type, int shared)
-{
-	FSRef ref;
-
-        /* First, get the path */
-	switch (type) {
-		case SYNCTERM_PATH_INI:
-		case SYNCTERM_PATH_LIST:
-		case SYNCTERM_PATH_KEYS:
-			if (FSFindFolder(shared ? kLocalDomain : kUserDomain, kPreferencesFolderType, kCreateFolder,
-			    &ref) != noErr)
-				return NULL;
-			if (FSRefMakePath(&ref, (unsigned char *)fn, fnlen) != noErr)
-				return NULL;
-			backslash(fn);
-			strncat(fn, "SyncTERM", fnlen - strlen(fn) - 1);
-			backslash(fn);
-			if (!isdir(fn)) {
-				if (MKDIR(fn))
-					return NULL;
-			}
-			break;
-
-		case SYNCTERM_DEFAULT_TRANSFER_PATH:
-                        /* I'd love to use the "right" setting here, but don't know how */
-			if (FSFindFolder(shared ? kLocalDomain : kUserDomain, kDownloadsFolderType, kCreateFolder,
-			    &ref) != noErr)
-				return NULL;
-			if (FSRefMakePath(&ref, (unsigned char *)fn, fnlen) != noErr)
-				return NULL;
-			backslash(fn);
-			if (!isdir(fn)) {
-				if (MKDIR(fn))
-					return NULL;
-			}
-			return fn;
-		case SYNCTERM_PATH_CACHE:
-			if (FSFindFolder(shared ? kLocalDomain : kUserDomain, kCachedDataFolderType, kCreateFolder,
-			    &ref) != noErr)
-				return NULL;
-			if (FSRefMakePath(&ref, (unsigned char *)fn, fnlen) != noErr)
-				return NULL;
-			backslash(fn);
-			return fn;
-	}
-
-	switch (type) {
-		case SYNCTERM_PATH_INI:
-			strncat(fn, "SyncTERM.ini", fnlen - strlen(fn) - 1);
-			return fn;
-		case SYNCTERM_PATH_LIST:
-			strncat(fn, "SyncTERM.lst", fnlen - strlen(fn) - 1);
-			return fn;
-		case SYNCTERM_PATH_KEYS:
-			strncat(fn, "SyncTERM.ssh", fnlen - strlen(fn) - 1);
-			return fn;
-	}
-	return NULL;
-}
-
 #elif defined(_WIN32) /* if defined(__APPLE__) && defined(__MACH__) */
 
 static char *