├── Mounting Yard
├── Art
│ ├── menu.png
│ ├── settings.png
│ ├── spotlight.png
│ └── standard_conenction_dialog.png
├── Assets.xcassets
│ ├── Contents.json
│ ├── menu-icons
│ │ ├── Contents.json
│ │ ├── icon-afp.imageset
│ │ │ ├── icon-afp-16x16.png
│ │ │ ├── icon-afp-16x16@2x.png
│ │ │ └── Contents.json
│ │ ├── icon-ftp.imageset
│ │ │ ├── icon-ftp-16x16.png
│ │ │ ├── icon-ftp-16x16@2x.png
│ │ │ └── Contents.json
│ │ ├── icon-smb.imageset
│ │ │ ├── icon-smb-16x16.png
│ │ │ ├── icon-smb-16x16@2x.png
│ │ │ └── Contents.json
│ │ ├── icon-vnc.imageset
│ │ │ ├── icon-vnc-16x16.png
│ │ │ ├── icon-vnc-16x16@2x.png
│ │ │ └── Contents.json
│ │ └── icon-unknown.imageset
│ │ │ ├── icon-unknown-16x16.png
│ │ │ ├── icon-unknown-16x16@2x.png
│ │ │ └── Contents.json
│ ├── Application Icons
│ │ ├── Contents.json
│ │ ├── AppIcon.appiconset
│ │ │ ├── icon_16x16.png
│ │ │ ├── icon_32x32.png
│ │ │ ├── icon_128x128.png
│ │ │ ├── icon_256x256.png
│ │ │ ├── icon_512x512.png
│ │ │ ├── icon_128x128@2x.png
│ │ │ ├── icon_16x16@2x.png
│ │ │ ├── icon_256x256@2x.png
│ │ │ ├── icon_32x32@2x.png
│ │ │ ├── icon_512x512@2x.png
│ │ │ └── Contents.json
│ │ ├── ArchiveIcon.iconset
│ │ │ ├── icon_16x16.png
│ │ │ ├── icon_32x32.png
│ │ │ ├── icon_128x128.png
│ │ │ ├── icon_16x16@2x.png
│ │ │ ├── icon_256x256.png
│ │ │ ├── icon_32x32@2x.png
│ │ │ ├── icon_512x512.png
│ │ │ ├── icon_128x128@2x.png
│ │ │ ├── icon_256x256@2x.png
│ │ │ └── icon_512x512@2x.png
│ │ └── DocumentIcon.iconset
│ │ │ ├── icon_16x16.png
│ │ │ ├── icon_32x32.png
│ │ │ ├── icon_128x128.png
│ │ │ ├── icon_16x16@2x.png
│ │ │ ├── icon_256x256.png
│ │ │ ├── icon_32x32@2x.png
│ │ │ ├── icon_512x512.png
│ │ │ ├── icon_128x128@2x.png
│ │ │ ├── icon_256x256@2x.png
│ │ │ └── icon_512x512@2x.png
│ └── MenuIcon.imageset
│ │ ├── Icon_16x16.png
│ │ ├── Icon_16x16@2x.png
│ │ └── Contents.json
├── Resources
│ ├── MenuIcons.xcf
│ ├── MenuIcons-16x16.xcf
│ ├── Credits.rtf
│ └── DSFMountingYardSettingsWindowController.xib
├── Mounting_Yard.entitlements
├── Mounting Yard.entitlements
├── DSFImageManager.swift
├── Info.plist
├── AppDelegate.swift
├── DSFMountingYardSettingsWindowController.swift
├── DSFMountingYardStatusMenu.swift
├── DSFMountingYardItem.swift
├── NetFSShare.swift
├── DSFMountingYardController.swift
└── Base.lproj
│ └── MainMenu.xib
├── Mounting Yard.xcodeproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
├── xcuserdata
│ └── dford.xcuserdatad
│ │ └── xcschemes
│ │ └── xcschememanagement.plist
└── project.pbxproj
├── Mounting PointTests
├── Info.plist
└── Mounting_PointTests.swift
├── LICENSE
└── README.md
/Mounting Yard/Art/menu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dagronf/MountingYard/HEAD/Mounting Yard/Art/menu.png
--------------------------------------------------------------------------------
/Mounting Yard/Art/settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dagronf/MountingYard/HEAD/Mounting Yard/Art/settings.png
--------------------------------------------------------------------------------
/Mounting Yard/Art/spotlight.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dagronf/MountingYard/HEAD/Mounting Yard/Art/spotlight.png
--------------------------------------------------------------------------------
/Mounting Yard/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/Mounting Yard/Resources/MenuIcons.xcf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dagronf/MountingYard/HEAD/Mounting Yard/Resources/MenuIcons.xcf
--------------------------------------------------------------------------------
/Mounting Yard/Assets.xcassets/menu-icons/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/Mounting Yard/Assets.xcassets/Application Icons/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/Mounting Yard/Resources/MenuIcons-16x16.xcf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dagronf/MountingYard/HEAD/Mounting Yard/Resources/MenuIcons-16x16.xcf
--------------------------------------------------------------------------------
/Mounting Yard/Art/standard_conenction_dialog.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dagronf/MountingYard/HEAD/Mounting Yard/Art/standard_conenction_dialog.png
--------------------------------------------------------------------------------
/Mounting Yard/Assets.xcassets/MenuIcon.imageset/Icon_16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dagronf/MountingYard/HEAD/Mounting Yard/Assets.xcassets/MenuIcon.imageset/Icon_16x16.png
--------------------------------------------------------------------------------
/Mounting Yard/Assets.xcassets/MenuIcon.imageset/Icon_16x16@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dagronf/MountingYard/HEAD/Mounting Yard/Assets.xcassets/MenuIcon.imageset/Icon_16x16@2x.png
--------------------------------------------------------------------------------
/Mounting Yard/Assets.xcassets/menu-icons/icon-afp.imageset/icon-afp-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dagronf/MountingYard/HEAD/Mounting Yard/Assets.xcassets/menu-icons/icon-afp.imageset/icon-afp-16x16.png
--------------------------------------------------------------------------------
/Mounting Yard/Assets.xcassets/menu-icons/icon-ftp.imageset/icon-ftp-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dagronf/MountingYard/HEAD/Mounting Yard/Assets.xcassets/menu-icons/icon-ftp.imageset/icon-ftp-16x16.png
--------------------------------------------------------------------------------
/Mounting Yard/Assets.xcassets/menu-icons/icon-smb.imageset/icon-smb-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dagronf/MountingYard/HEAD/Mounting Yard/Assets.xcassets/menu-icons/icon-smb.imageset/icon-smb-16x16.png
--------------------------------------------------------------------------------
/Mounting Yard/Assets.xcassets/menu-icons/icon-vnc.imageset/icon-vnc-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dagronf/MountingYard/HEAD/Mounting Yard/Assets.xcassets/menu-icons/icon-vnc.imageset/icon-vnc-16x16.png
--------------------------------------------------------------------------------
/Mounting Yard/Assets.xcassets/Application Icons/AppIcon.appiconset/icon_16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dagronf/MountingYard/HEAD/Mounting Yard/Assets.xcassets/Application Icons/AppIcon.appiconset/icon_16x16.png
--------------------------------------------------------------------------------
/Mounting Yard/Assets.xcassets/Application Icons/AppIcon.appiconset/icon_32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dagronf/MountingYard/HEAD/Mounting Yard/Assets.xcassets/Application Icons/AppIcon.appiconset/icon_32x32.png
--------------------------------------------------------------------------------
/Mounting Yard/Assets.xcassets/menu-icons/icon-afp.imageset/icon-afp-16x16@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dagronf/MountingYard/HEAD/Mounting Yard/Assets.xcassets/menu-icons/icon-afp.imageset/icon-afp-16x16@2x.png
--------------------------------------------------------------------------------
/Mounting Yard/Assets.xcassets/menu-icons/icon-ftp.imageset/icon-ftp-16x16@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dagronf/MountingYard/HEAD/Mounting Yard/Assets.xcassets/menu-icons/icon-ftp.imageset/icon-ftp-16x16@2x.png
--------------------------------------------------------------------------------
/Mounting Yard/Assets.xcassets/menu-icons/icon-smb.imageset/icon-smb-16x16@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dagronf/MountingYard/HEAD/Mounting Yard/Assets.xcassets/menu-icons/icon-smb.imageset/icon-smb-16x16@2x.png
--------------------------------------------------------------------------------
/Mounting Yard/Assets.xcassets/menu-icons/icon-vnc.imageset/icon-vnc-16x16@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dagronf/MountingYard/HEAD/Mounting Yard/Assets.xcassets/menu-icons/icon-vnc.imageset/icon-vnc-16x16@2x.png
--------------------------------------------------------------------------------
/Mounting Yard/Assets.xcassets/Application Icons/AppIcon.appiconset/icon_128x128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dagronf/MountingYard/HEAD/Mounting Yard/Assets.xcassets/Application Icons/AppIcon.appiconset/icon_128x128.png
--------------------------------------------------------------------------------
/Mounting Yard/Assets.xcassets/Application Icons/AppIcon.appiconset/icon_256x256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dagronf/MountingYard/HEAD/Mounting Yard/Assets.xcassets/Application Icons/AppIcon.appiconset/icon_256x256.png
--------------------------------------------------------------------------------
/Mounting Yard/Assets.xcassets/Application Icons/AppIcon.appiconset/icon_512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dagronf/MountingYard/HEAD/Mounting Yard/Assets.xcassets/Application Icons/AppIcon.appiconset/icon_512x512.png
--------------------------------------------------------------------------------
/Mounting Yard/Assets.xcassets/Application Icons/ArchiveIcon.iconset/icon_16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dagronf/MountingYard/HEAD/Mounting Yard/Assets.xcassets/Application Icons/ArchiveIcon.iconset/icon_16x16.png
--------------------------------------------------------------------------------
/Mounting Yard/Assets.xcassets/Application Icons/ArchiveIcon.iconset/icon_32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dagronf/MountingYard/HEAD/Mounting Yard/Assets.xcassets/Application Icons/ArchiveIcon.iconset/icon_32x32.png
--------------------------------------------------------------------------------
/Mounting Yard/Assets.xcassets/Application Icons/DocumentIcon.iconset/icon_16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dagronf/MountingYard/HEAD/Mounting Yard/Assets.xcassets/Application Icons/DocumentIcon.iconset/icon_16x16.png
--------------------------------------------------------------------------------
/Mounting Yard/Assets.xcassets/Application Icons/DocumentIcon.iconset/icon_32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dagronf/MountingYard/HEAD/Mounting Yard/Assets.xcassets/Application Icons/DocumentIcon.iconset/icon_32x32.png
--------------------------------------------------------------------------------
/Mounting Yard/Assets.xcassets/Application Icons/AppIcon.appiconset/icon_128x128@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dagronf/MountingYard/HEAD/Mounting Yard/Assets.xcassets/Application Icons/AppIcon.appiconset/icon_128x128@2x.png
--------------------------------------------------------------------------------
/Mounting Yard/Assets.xcassets/Application Icons/AppIcon.appiconset/icon_16x16@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dagronf/MountingYard/HEAD/Mounting Yard/Assets.xcassets/Application Icons/AppIcon.appiconset/icon_16x16@2x.png
--------------------------------------------------------------------------------
/Mounting Yard/Assets.xcassets/Application Icons/AppIcon.appiconset/icon_256x256@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dagronf/MountingYard/HEAD/Mounting Yard/Assets.xcassets/Application Icons/AppIcon.appiconset/icon_256x256@2x.png
--------------------------------------------------------------------------------
/Mounting Yard/Assets.xcassets/Application Icons/AppIcon.appiconset/icon_32x32@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dagronf/MountingYard/HEAD/Mounting Yard/Assets.xcassets/Application Icons/AppIcon.appiconset/icon_32x32@2x.png
--------------------------------------------------------------------------------
/Mounting Yard/Assets.xcassets/Application Icons/AppIcon.appiconset/icon_512x512@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dagronf/MountingYard/HEAD/Mounting Yard/Assets.xcassets/Application Icons/AppIcon.appiconset/icon_512x512@2x.png
--------------------------------------------------------------------------------
/Mounting Yard/Assets.xcassets/Application Icons/ArchiveIcon.iconset/icon_128x128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dagronf/MountingYard/HEAD/Mounting Yard/Assets.xcassets/Application Icons/ArchiveIcon.iconset/icon_128x128.png
--------------------------------------------------------------------------------
/Mounting Yard/Assets.xcassets/Application Icons/ArchiveIcon.iconset/icon_16x16@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dagronf/MountingYard/HEAD/Mounting Yard/Assets.xcassets/Application Icons/ArchiveIcon.iconset/icon_16x16@2x.png
--------------------------------------------------------------------------------
/Mounting Yard/Assets.xcassets/Application Icons/ArchiveIcon.iconset/icon_256x256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dagronf/MountingYard/HEAD/Mounting Yard/Assets.xcassets/Application Icons/ArchiveIcon.iconset/icon_256x256.png
--------------------------------------------------------------------------------
/Mounting Yard/Assets.xcassets/Application Icons/ArchiveIcon.iconset/icon_32x32@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dagronf/MountingYard/HEAD/Mounting Yard/Assets.xcassets/Application Icons/ArchiveIcon.iconset/icon_32x32@2x.png
--------------------------------------------------------------------------------
/Mounting Yard/Assets.xcassets/Application Icons/ArchiveIcon.iconset/icon_512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dagronf/MountingYard/HEAD/Mounting Yard/Assets.xcassets/Application Icons/ArchiveIcon.iconset/icon_512x512.png
--------------------------------------------------------------------------------
/Mounting Yard/Assets.xcassets/Application Icons/DocumentIcon.iconset/icon_128x128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dagronf/MountingYard/HEAD/Mounting Yard/Assets.xcassets/Application Icons/DocumentIcon.iconset/icon_128x128.png
--------------------------------------------------------------------------------
/Mounting Yard/Assets.xcassets/Application Icons/DocumentIcon.iconset/icon_16x16@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dagronf/MountingYard/HEAD/Mounting Yard/Assets.xcassets/Application Icons/DocumentIcon.iconset/icon_16x16@2x.png
--------------------------------------------------------------------------------
/Mounting Yard/Assets.xcassets/Application Icons/DocumentIcon.iconset/icon_256x256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dagronf/MountingYard/HEAD/Mounting Yard/Assets.xcassets/Application Icons/DocumentIcon.iconset/icon_256x256.png
--------------------------------------------------------------------------------
/Mounting Yard/Assets.xcassets/Application Icons/DocumentIcon.iconset/icon_32x32@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dagronf/MountingYard/HEAD/Mounting Yard/Assets.xcassets/Application Icons/DocumentIcon.iconset/icon_32x32@2x.png
--------------------------------------------------------------------------------
/Mounting Yard/Assets.xcassets/Application Icons/DocumentIcon.iconset/icon_512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dagronf/MountingYard/HEAD/Mounting Yard/Assets.xcassets/Application Icons/DocumentIcon.iconset/icon_512x512.png
--------------------------------------------------------------------------------
/Mounting Yard/Assets.xcassets/menu-icons/icon-unknown.imageset/icon-unknown-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dagronf/MountingYard/HEAD/Mounting Yard/Assets.xcassets/menu-icons/icon-unknown.imageset/icon-unknown-16x16.png
--------------------------------------------------------------------------------
/Mounting Yard/Assets.xcassets/Application Icons/ArchiveIcon.iconset/icon_128x128@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dagronf/MountingYard/HEAD/Mounting Yard/Assets.xcassets/Application Icons/ArchiveIcon.iconset/icon_128x128@2x.png
--------------------------------------------------------------------------------
/Mounting Yard/Assets.xcassets/Application Icons/ArchiveIcon.iconset/icon_256x256@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dagronf/MountingYard/HEAD/Mounting Yard/Assets.xcassets/Application Icons/ArchiveIcon.iconset/icon_256x256@2x.png
--------------------------------------------------------------------------------
/Mounting Yard/Assets.xcassets/Application Icons/ArchiveIcon.iconset/icon_512x512@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dagronf/MountingYard/HEAD/Mounting Yard/Assets.xcassets/Application Icons/ArchiveIcon.iconset/icon_512x512@2x.png
--------------------------------------------------------------------------------
/Mounting Yard/Assets.xcassets/Application Icons/DocumentIcon.iconset/icon_128x128@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dagronf/MountingYard/HEAD/Mounting Yard/Assets.xcassets/Application Icons/DocumentIcon.iconset/icon_128x128@2x.png
--------------------------------------------------------------------------------
/Mounting Yard/Assets.xcassets/Application Icons/DocumentIcon.iconset/icon_256x256@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dagronf/MountingYard/HEAD/Mounting Yard/Assets.xcassets/Application Icons/DocumentIcon.iconset/icon_256x256@2x.png
--------------------------------------------------------------------------------
/Mounting Yard/Assets.xcassets/Application Icons/DocumentIcon.iconset/icon_512x512@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dagronf/MountingYard/HEAD/Mounting Yard/Assets.xcassets/Application Icons/DocumentIcon.iconset/icon_512x512@2x.png
--------------------------------------------------------------------------------
/Mounting Yard/Assets.xcassets/menu-icons/icon-unknown.imageset/icon-unknown-16x16@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dagronf/MountingYard/HEAD/Mounting Yard/Assets.xcassets/menu-icons/icon-unknown.imageset/icon-unknown-16x16@2x.png
--------------------------------------------------------------------------------
/Mounting Yard/Mounting_Yard.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/Mounting Yard.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Mounting Yard.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Mounting Yard/Mounting Yard.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.security.app-sandbox
6 |
7 | com.apple.security.files.user-selected.read-write
8 |
9 | com.apple.security.network.client
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/Mounting Yard/Resources/Credits.rtf:
--------------------------------------------------------------------------------
1 | {\rtf1\ansi\ansicpg1252\cocoartf1561\cocoasubrtf600
2 | {\fonttbl\f0\fswiss\fcharset0 Helvetica;}
3 | {\colortbl;\red255\green255\blue255;\red0\green0\blue0;}
4 | {\*\expandedcolortbl;;\csgray\c0\c0;}
5 | \paperw11900\paperh16840\margl1440\margr1440\vieww10800\viewh8400\viewkind0
6 | \pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural\partightenfactor0
7 |
8 | \f0\fs26 \cf0 \cb2 \
9 | }
--------------------------------------------------------------------------------
/Mounting Yard/Assets.xcassets/MenuIcon.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "Icon_16x16.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "Icon_16x16@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/Mounting Yard/Assets.xcassets/menu-icons/icon-afp.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon-afp-16x16.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "icon-afp-16x16@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/Mounting Yard/Assets.xcassets/menu-icons/icon-ftp.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon-ftp-16x16.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "icon-ftp-16x16@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/Mounting Yard/Assets.xcassets/menu-icons/icon-smb.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon-smb-16x16.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "icon-smb-16x16@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/Mounting Yard/Assets.xcassets/menu-icons/icon-vnc.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon-vnc-16x16.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "icon-vnc-16x16@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/Mounting Yard/Assets.xcassets/menu-icons/icon-unknown.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon-unknown-16x16.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "icon-unknown-16x16@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/Mounting Yard.xcodeproj/xcuserdata/dford.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | Mounting Point.xcscheme
8 |
9 | orderHint
10 | 0
11 |
12 | Mounting Yard Spotlight Importer.xcscheme
13 |
14 | orderHint
15 | 1
16 |
17 | Mounting Yard.xcscheme
18 |
19 | orderHint
20 | 0
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/Mounting PointTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Darren Ford
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/Mounting PointTests/Mounting_PointTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Mounting_PointTests.swift
3 | // Mounting PointTests
4 | //
5 | // Created by Darren Ford on 31/7/18.
6 | // Copyright © 2018 Darren Ford. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import Mounting_Point
11 |
12 | class Mounting_PointTests: XCTestCase {
13 |
14 | override func setUp() {
15 | super.setUp()
16 | // Put setup code here. This method is called before the invocation of each test method in the class.
17 | }
18 |
19 | override func tearDown() {
20 | // Put teardown code here. This method is called after the invocation of each test method in the class.
21 | super.tearDown()
22 | }
23 |
24 | func testExample() {
25 | // This is an example of a functional test case.
26 | // Use XCTAssert and related functions to verify your tests produce the correct results.
27 | }
28 |
29 | func testPerformanceExample() {
30 | // This is an example of a performance test case.
31 | self.measure {
32 | // Put the code you want to measure the time of here.
33 | }
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/Mounting Yard/Assets.xcassets/Application Icons/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "16x16",
5 | "idiom" : "mac",
6 | "filename" : "icon_16x16.png",
7 | "scale" : "1x"
8 | },
9 | {
10 | "size" : "16x16",
11 | "idiom" : "mac",
12 | "filename" : "icon_16x16@2x.png",
13 | "scale" : "2x"
14 | },
15 | {
16 | "size" : "32x32",
17 | "idiom" : "mac",
18 | "filename" : "icon_32x32.png",
19 | "scale" : "1x"
20 | },
21 | {
22 | "size" : "32x32",
23 | "idiom" : "mac",
24 | "filename" : "icon_32x32@2x.png",
25 | "scale" : "2x"
26 | },
27 | {
28 | "size" : "128x128",
29 | "idiom" : "mac",
30 | "filename" : "icon_128x128.png",
31 | "scale" : "1x"
32 | },
33 | {
34 | "size" : "128x128",
35 | "idiom" : "mac",
36 | "filename" : "icon_128x128@2x.png",
37 | "scale" : "2x"
38 | },
39 | {
40 | "size" : "256x256",
41 | "idiom" : "mac",
42 | "filename" : "icon_256x256.png",
43 | "scale" : "1x"
44 | },
45 | {
46 | "size" : "256x256",
47 | "idiom" : "mac",
48 | "filename" : "icon_256x256@2x.png",
49 | "scale" : "2x"
50 | },
51 | {
52 | "size" : "512x512",
53 | "idiom" : "mac",
54 | "filename" : "icon_512x512.png",
55 | "scale" : "1x"
56 | },
57 | {
58 | "size" : "512x512",
59 | "idiom" : "mac",
60 | "filename" : "icon_512x512@2x.png",
61 | "scale" : "2x"
62 | }
63 | ],
64 | "info" : {
65 | "version" : 1,
66 | "author" : "xcode"
67 | }
68 | }
--------------------------------------------------------------------------------
/Mounting Yard/DSFImageManager.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DSFImageManager.swift
3 | // Mounting Yard
4 | //
5 | // Created by Darren Ford on 4/8/18.
6 | // Copyright © 2018 Darren Ford. All rights reserved.
7 | //
8 |
9 | // MIT License
10 | //
11 | // Copyright (c) 2018 Darren Ford
12 | //
13 | // Permission is hereby granted, free of charge, to any person obtaining a copy
14 | // of this software and associated documentation files (the "Software"), to deal
15 | // in the Software without restriction, including without limitation the rights
16 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 | // copies of the Software, and to permit persons to whom the Software is
18 | // furnished to do so, subject to the following conditions:
19 | //
20 | // The above copyright notice and this permission notice shall be included in all
21 | // copies or substantial portions of the Software.
22 | //
23 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29 | // SOFTWARE.
30 |
31 | import Cocoa
32 |
33 | class DSFImageManager
34 | {
35 | static func afpImage() -> NSImage
36 | {
37 | return NSImage(named: NSImage.Name(rawValue: "icon-afp"))!
38 | }
39 |
40 | static func ftpImage() -> NSImage
41 | {
42 | return NSImage(named: NSImage.Name(rawValue: "icon-ftp"))!
43 | }
44 |
45 | static func smbImage() -> NSImage
46 | {
47 | return NSImage(named: NSImage.Name(rawValue: "icon-smb"))!
48 | }
49 |
50 | static func vncImage() -> NSImage
51 | {
52 | return NSImage(named: NSImage.Name(rawValue: "icon-vnc"))!
53 | }
54 |
55 | static func unknownImage() -> NSImage
56 | {
57 | return NSImage(named: NSImage.Name(rawValue: "icon-unknown"))!
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/Mounting Yard/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleDocumentTypes
8 |
9 |
10 | CFBundleTypeExtensions
11 |
12 | mountingYard
13 |
14 | CFBundleTypeIconFile
15 | DocumentIcon
16 | CFBundleTypeName
17 | Mounting Yard Document
18 | CFBundleTypeRole
19 | Editor
20 | NSDocumentClass
21 |
22 |
23 |
24 | CFBundleTypeExtensions
25 |
26 | mountingYardArchive
27 |
28 | CFBundleTypeIconFile
29 | ArchiveIcon
30 | CFBundleTypeName
31 | Mounting Yard Archive
32 | CFBundleTypeRole
33 | Editor
34 |
35 |
36 | CFBundleExecutable
37 | $(EXECUTABLE_NAME)
38 | CFBundleIconFile
39 |
40 | CFBundleIdentifier
41 | $(PRODUCT_BUNDLE_IDENTIFIER)
42 | CFBundleInfoDictionaryVersion
43 | 6.0
44 | CFBundleName
45 | $(PRODUCT_NAME)
46 | CFBundlePackageType
47 | APPL
48 | CFBundleShortVersionString
49 | 1.2
50 | CFBundleVersion
51 | 1
52 | LSApplicationCategoryType
53 | public.app-category.utilities
54 | LSMinimumSystemVersion
55 | $(MACOSX_DEPLOYMENT_TARGET)
56 | LSUIElement
57 |
58 | NSHumanReadableCopyright
59 | Copyright © 2018 Darren Ford. All rights reserved.
60 | NSMainNibFile
61 | MainMenu
62 | NSPrincipalClass
63 | NSApplication
64 |
65 |
66 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Mounting Yard
2 |
3 | A simple Mac application that allows you to see and connect to your favourite mount points in the menu bar.
4 |
5 | The functionality provided by the finder (using the 'Connect to Server…' menu) is great, however means that you have to have the finder active in order to quickly connect. Additionally the finder UI does not support friendly naming, thus you have to understand the difference between (eg) `smb://144.33.1.1` and `smb://144.33.1.2` in your brainz if your connection points are not mapped within a DNS
6 |
7 | Supported mount point types :-
8 |
9 | * `afp://`
10 | * `smb://`
11 | * `cifs://`
12 | * `ftp://`
13 |
14 | If a scheme is provided that the application doesn't support, it passes it on to the Finder to attempt to locate a program to support the URL.
15 |
16 | For example :-
17 |
18 | * `vnc://` (opens Screen Sharing)
19 | * `rdp://` (if you have Microsoft Remote Desktop installed, it will attempt to open it)
20 |
21 |
22 | ## Interface
23 | The main interface lives in the menu bar, with a menu to allow your mounting points to be quickly accessed.
24 |
25 | 
26 |
27 | ## Settings
28 |
29 | The stored mounting points are accessed via the `Settings…` menu from the main Mounting Point menu.
30 |
31 | 
32 |
33 | Note that this version doesn't support storing passwords. If you want automatic connection to a mount point use the standard server connection dialog that appears when you connect to a server to remember the password in the keychain.
34 |
35 | 
36 |
37 | ## Spotlight
38 |
39 | Mounting Yard stores the settings for a server as a file on your hard drive, which is indexed by Spotlight. Thus, you can use spotlight to quickly access a mount point (even if its not currently connected) with a simple spotlight search
40 |
41 | Due to sandbox restrictions, the files are stored in
42 |
43 | `/Users//Library/Containers/com.darrenford.Mounting-Yard/Data/Documents/`
44 |
45 | which allows for both spotlight indexing and time machine backups
46 |
47 | 
48 |
--------------------------------------------------------------------------------
/Mounting Yard/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // Mounting Point
4 | //
5 | // Created by Darren Ford on 31/7/18.
6 | // Copyright © 2018 Darren Ford. All rights reserved.
7 | //
8 |
9 | // MIT License
10 | //
11 | // Copyright (c) 2018 Darren Ford
12 | //
13 | // Permission is hereby granted, free of charge, to any person obtaining a copy
14 | // of this software and associated documentation files (the "Software"), to deal
15 | // in the Software without restriction, including without limitation the rights
16 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 | // copies of the Software, and to permit persons to whom the Software is
18 | // furnished to do so, subject to the following conditions:
19 | //
20 | // The above copyright notice and this permission notice shall be included in all
21 | // copies or substantial portions of the Software.
22 | //
23 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29 | // SOFTWARE.
30 |
31 | import Cocoa
32 |
33 | @NSApplicationMain
34 | class AppDelegate: NSObject, NSApplicationDelegate
35 | {
36 | @IBOutlet var window: NSWindow!
37 |
38 | lazy var mountingYard: DSFMountingYardController =
39 | {
40 | let yard = DSFMountingYardController()
41 | yard.load()
42 | return yard
43 | }()
44 |
45 | lazy var statusManager: DSFMountingYardStatusMenu =
46 | {
47 | let manager = DSFMountingYardStatusMenu()
48 | manager.configure(controller: self.mountingYard)
49 | return manager
50 | }()
51 |
52 | lazy var settingsWindow: DSFMountingYardSettingsWindowController =
53 | {
54 | let wc = DSFMountingYardSettingsWindowController(windowNibName: NSNib.Name(rawValue: "DSFMountingYardSettingsWindowController"))
55 | wc.mountingYard = mountingYard
56 | return wc
57 | }()
58 |
59 | private func initialize()
60 | {
61 | // Kinda dumb, simple tho!
62 | _ = self.statusManager
63 | }
64 |
65 | func application(_: NSApplication, openFile filename: String) -> Bool
66 | {
67 | self.initialize()
68 | return self.mountingYard.openFile(filename: filename)
69 | }
70 |
71 | func applicationDidFinishLaunching(_: Notification)
72 | {
73 | self.initialize()
74 |
75 | // If there's no entries, display the settings window by default
76 | if self.mountingYard.items.count == 0
77 | {
78 | self.showSettings()
79 | }
80 | }
81 |
82 | func applicationWillTerminate(_: Notification)
83 | {
84 | // Sync any changes
85 | _ = self.mountingYard.save()
86 | }
87 |
88 | func showSettings()
89 | {
90 | NSApp.activate(ignoringOtherApps: true)
91 | self.settingsWindow.window?.makeKeyAndOrderFront(self)
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/Mounting Yard/DSFMountingYardSettingsWindowController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DSFMountingYardSettingsWindowController.swift
3 | // Mounting Yard
4 | //
5 | // Created by Darren Ford on 3/8/18.
6 | // Copyright © 2018 Darren Ford. All rights reserved.
7 | //
8 |
9 | // MIT License
10 | //
11 | // Copyright (c) 2018 Darren Ford
12 | //
13 | // Permission is hereby granted, free of charge, to any person obtaining a copy
14 | // of this software and associated documentation files (the "Software"), to deal
15 | // in the Software without restriction, including without limitation the rights
16 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 | // copies of the Software, and to permit persons to whom the Software is
18 | // furnished to do so, subject to the following conditions:
19 | //
20 | // The above copyright notice and this permission notice shall be included in all
21 | // copies or substantial portions of the Software.
22 | //
23 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29 | // SOFTWARE.
30 |
31 | import Cocoa
32 |
33 | class DSFMountingYardSettingsWindowController: NSWindowController, NSWindowDelegate, NSTextFieldDelegate
34 | {
35 | @objc var mountingYard: DSFMountingYardController?
36 |
37 | @IBOutlet var nameField: NSTextField!
38 | @IBOutlet var addressField: NSTextField!
39 |
40 | @IBOutlet var itemsArrayController: NSArrayController!
41 |
42 | override func windowDidLoad()
43 | {
44 | super.windowDidLoad()
45 |
46 | self.window!.isMovableByWindowBackground = true
47 |
48 | // Implement this method to handle any initialization after your window controller's window has been loaded from its nib file.
49 | }
50 |
51 | @objc func yardController() -> DSFMountingYardController
52 | {
53 | return self.mountingYard!
54 | }
55 |
56 | func windowDidResignKey(_: Notification)
57 | {
58 | // If the settings window disappears, sync the updates to disk
59 | self.window?.makeFirstResponder(nil)
60 | _ = self.yardController().save()
61 | }
62 |
63 | @IBAction func addItem(_ sender: Any)
64 | {
65 | self.itemsArrayController.add(sender)
66 |
67 | if self.itemsArrayController.selectedObjects.first != nil
68 | {
69 | self.nameField.selectText(nil)
70 | }
71 | }
72 |
73 | override func controlTextDidChange(_ obj: Notification)
74 | {
75 | if let control = obj.object as? NSTextField,
76 | control === self.addressField
77 | {
78 | // For the address field, validate every keypress
79 | if let item = self.itemsArrayController.selectedObjects.first as? DSFMountingYardItem
80 | {
81 | item.address = control.stringValue
82 | }
83 | }
84 | }
85 |
86 | private func updateNameIfDuplicateFound(_ item: DSFMountingYardItem, updatedName: String)
87 | {
88 | for otherItem in self.itemsArrayController.arrangedObjects as! [DSFMountingYardItem]
89 | {
90 | if otherItem !== item,
91 | otherItem.name == updatedName
92 | {
93 | var newName = updatedName
94 | newName.append(" ")
95 | newName.append(NSLocalizedString("Copy", comment: "The string that gets appended to the name if its a duplicate"))
96 | if let item = self.itemsArrayController.selectedObjects.first as? DSFMountingYardItem
97 | {
98 | item.name = newName
99 | }
100 | break
101 | }
102 | }
103 | }
104 |
105 | override func controlTextDidEndEditing(_ obj: Notification)
106 | {
107 | // If the name field completes, update it to make it unique
108 |
109 | // This appears to get called AFTER the array controller has updated the content.
110 |
111 | if let control = obj.object as? NSTextField,
112 | let item = self.itemsArrayController.selectedObjects.first as? DSFMountingYardItem,
113 | control === self.nameField
114 | {
115 | if item.name.count == 0
116 | {
117 | item.name = "empty"
118 | }
119 | self.updateNameIfDuplicateFound(item, updatedName: control.stringValue)
120 | }
121 | }
122 |
123 | @IBAction func testConnection(_: Any)
124 | {
125 | if let item = itemsArrayController.selectedObjects.first as? DSFMountingYardItem
126 | {
127 | _ = self.yardController().mount(item: item)
128 | }
129 | }
130 |
131 | @IBAction func actionButton(_ sender: NSButton)
132 | {
133 | NSMenu.popUpContextMenu(sender.menu!,
134 | with: NSApp.currentEvent!,
135 | for: sender)
136 | }
137 |
138 | @IBAction func share(_: Any)
139 | {
140 | _ = self.yardController().shareItems()
141 | }
142 |
143 | @IBAction func importData(_: Any)
144 | {
145 | _ = self.yardController().importItems()
146 | }
147 | }
148 |
--------------------------------------------------------------------------------
/Mounting Yard/DSFMountingYardStatusMenu.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DSFMountingYardStatusMenu.swift
3 | // Mounting Point
4 | //
5 | // Created by Darren Ford on 31/7/18.
6 | // Copyright © 2018 Darren Ford. All rights reserved.
7 | //
8 |
9 | // MIT License
10 | //
11 | // Copyright (c) 2018 Darren Ford
12 | //
13 | // Permission is hereby granted, free of charge, to any person obtaining a copy
14 | // of this software and associated documentation files (the "Software"), to deal
15 | // in the Software without restriction, including without limitation the rights
16 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 | // copies of the Software, and to permit persons to whom the Software is
18 | // furnished to do so, subject to the following conditions:
19 | //
20 | // The above copyright notice and this permission notice shall be included in all
21 | // copies or substantial portions of the Software.
22 | //
23 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29 | // SOFTWARE.
30 |
31 | import Cocoa
32 |
33 | class DSFMountingYardStatusMenu: NSObject, NSMenuDelegate
34 | {
35 | let statusBar = NSStatusBar.system.statusItem(withLength: 30)
36 | let statusMenu = NSMenu()
37 |
38 | var controller: DSFMountingYardController?
39 |
40 | private lazy var settingsMenu: NSMenuItem =
41 | {
42 | let settingsMenu = NSMenuItem(
43 | title: NSLocalizedString("Settings…", comment: "Settings menu entry"),
44 | action: #selector(self.showSettings(_:)),
45 | keyEquivalent: ""
46 | )
47 | settingsMenu.target = self
48 | settingsMenu.isEnabled = true
49 | return settingsMenu
50 | }()
51 |
52 | private lazy var aboutMenu: NSMenuItem =
53 | {
54 | let aboutMenu = NSMenuItem(
55 | title: NSLocalizedString("About Mounting Yard…", comment: "About menu entry"),
56 | action: #selector(self.showAbout(_:)),
57 | keyEquivalent: ""
58 | )
59 | aboutMenu.target = self
60 | aboutMenu.isEnabled = true
61 | return aboutMenu
62 | }()
63 |
64 | private lazy var quitMenu: NSMenuItem =
65 | {
66 | let quitMenu = NSMenuItem(
67 | title: NSLocalizedString("Quit", comment: "Quit menu entry"),
68 | action: #selector(NSApplication.terminate(_:)),
69 | keyEquivalent: ""
70 | )
71 | quitMenu.target = NSApplication.shared
72 | quitMenu.isEnabled = true
73 | return quitMenu
74 | }()
75 |
76 | func configure(controller: DSFMountingYardController)
77 | {
78 | self.controller = controller
79 |
80 | let menuIcon = NSImage(named: NSImage.Name(rawValue: "MenuIcon"))
81 | menuIcon!.isTemplate = true
82 | statusBar.image = menuIcon
83 | statusBar.menu = statusMenu
84 | statusMenu.delegate = self
85 | }
86 |
87 | func menuWillOpen(_ menu: NSMenu)
88 | {
89 | menu.removeAllItems()
90 | self.configureMenu()
91 | }
92 |
93 | private func resize(image: NSImage, w: Int, h: Int) -> NSImage
94 | {
95 | let destSize = NSMakeSize(CGFloat(w), CGFloat(h))
96 | let newImage = NSImage(size: destSize)
97 | newImage.lockFocus()
98 | image.draw(
99 | in: NSMakeRect(0, 0, destSize.width, destSize.height),
100 | from: NSMakeRect(0, 0, image.size.width, image.size.height),
101 | operation: .sourceOver,
102 | fraction: CGFloat(1)
103 | )
104 | newImage.unlockFocus()
105 | newImage.size = destSize
106 | return NSImage(data: newImage.tiffRepresentation!)!
107 | }
108 |
109 | private func configureMenu()
110 | {
111 | // Sort the items in the correct order
112 | var items = controller!.items
113 | items.sort { $0.name.lowercased() < $1.name.lowercased() }
114 |
115 | for item in items
116 | {
117 | let itemMenu = NSMenuItem(
118 | title: item.name,
119 | action: #selector(self.openItem(_:)),
120 | keyEquivalent: ""
121 | )
122 | itemMenu.representedObject = item
123 | itemMenu.target = self
124 | itemMenu.isEnabled = true
125 | itemMenu.image = item.icon
126 |
127 | self.statusMenu.addItem(itemMenu)
128 | }
129 |
130 | self.statusMenu.addItem(NSMenuItem.separator())
131 | self.statusMenu.addItem(self.settingsMenu)
132 | self.statusMenu.addItem(self.aboutMenu)
133 | self.statusMenu.addItem(NSMenuItem.separator())
134 | self.statusMenu.addItem(self.quitMenu)
135 | }
136 |
137 | @objc func openItem(_ sender: NSMenuItem)
138 | {
139 | self.controller!.mount(item: sender.representedObject as! DSFMountingYardItem)
140 | }
141 |
142 | @objc func showAbout(_: NSMenuItem)
143 | {
144 | NSApp.orderFrontStandardAboutPanel(self)
145 | }
146 |
147 | @objc func showSettings(_: NSMenuItem)
148 | {
149 | if let delegate = NSApp.delegate as? AppDelegate
150 | {
151 | delegate.showSettings()
152 | }
153 | }
154 | }
155 |
--------------------------------------------------------------------------------
/Mounting Yard/DSFMountingYardItem.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DSFMountingYardItem.swift
3 | // Mounting Yard
4 | //
5 | // Created by Darren Ford on 31/7/18.
6 | // Copyright © 2018 Darren Ford. All rights reserved.
7 | //
8 |
9 | // MIT License
10 | //
11 | // Copyright (c) 2018 Darren Ford
12 | //
13 | // Permission is hereby granted, free of charge, to any person obtaining a copy
14 | // of this software and associated documentation files (the "Software"), to deal
15 | // in the Software without restriction, including without limitation the rights
16 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 | // copies of the Software, and to permit persons to whom the Software is
18 | // furnished to do so, subject to the following conditions:
19 | //
20 | // The above copyright notice and this permission notice shall be included in all
21 | // copies or substantial portions of the Software.
22 | //
23 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29 | // SOFTWARE.
30 |
31 | import Cocoa
32 |
33 | @objc(DSFMountingYardItem)
34 | public class DSFMountingYardItem: NSObject
35 | {
36 | var url: URL?
37 | var modified: Bool = false
38 |
39 | static var detector: NSDataDetector = {
40 | let types: NSTextCheckingResult.CheckingType = [.link]
41 | let detector = try? NSDataDetector(types: types.rawValue)
42 | return detector!
43 | }()
44 |
45 | @objc dynamic var urlValid: Bool
46 | {
47 | if DSFMountingYardItem.detector.numberOfMatches(
48 | in: self.address,
49 | options: NSRegularExpression.MatchingOptions(rawValue: 0),
50 | range: NSMakeRange(0, self.address.count)
51 | ) > 0
52 | {
53 | return true
54 | }
55 | return false
56 | }
57 |
58 | @objc dynamic var name: String = ""
59 | {
60 | didSet
61 | {
62 | // File url is now out of sync. Clear it
63 | self.url = nil
64 | self.modified = true
65 | }
66 | }
67 |
68 | @objc dynamic var icon: NSImage = DSFImageManager.unknownImage()
69 |
70 | @objc dynamic var address: String = ""
71 | {
72 | didSet
73 | {
74 | self.willChangeValue(forKey: "urlValid")
75 | self.modified = true
76 | self.didChangeValue(forKey: "urlValid")
77 |
78 | self.syncIcon()
79 | }
80 | }
81 |
82 | @objc dynamic var username: String = ""
83 | {
84 | didSet
85 | {
86 | self.modified = true
87 | }
88 | }
89 |
90 | @objc dynamic var guest: Bool = false
91 | {
92 | didSet
93 | {
94 | self.modified = true
95 | }
96 | }
97 |
98 | @objc dynamic var mountedPoint: URL?
99 | {
100 | didSet
101 | {
102 | self.modified = true
103 | }
104 | }
105 |
106 | var connecting: Bool = false
107 |
108 | func validatedMountPoint() -> URL?
109 | {
110 | var b: ObjCBool = false
111 | if let mountPoint = self.mountedPoint
112 | {
113 | if FileManager.default.fileExists(atPath: mountPoint.path, isDirectory: &b)
114 | {
115 | return mountPoint
116 | }
117 | else
118 | {
119 | // The mount point doesn't exist anymore -- the user might have ejected it!
120 | self.mountedPoint = nil
121 | }
122 | }
123 | return nil
124 | }
125 |
126 | public override init()
127 | {
128 | super.init()
129 |
130 | // Dummy values for new object
131 | self.name = "new server"
132 | self.address = "scheme://localhost"
133 | self.syncIcon()
134 | }
135 |
136 | public init(url: URL, address: String, username: String, guest: Bool = false)
137 | {
138 | super.init()
139 |
140 | self.url = url
141 | self.name = (url.lastPathComponent as NSString).deletingPathExtension
142 | self.address = address
143 | self.username = username
144 | self.guest = guest
145 |
146 | self.syncIcon()
147 | }
148 |
149 | func syncIcon()
150 | {
151 | self.willChangeValue(forKey: "icon")
152 | self.modified = true
153 |
154 | let url = URL(string: address)
155 | switch url?.scheme
156 | {
157 | case "afp":
158 | self.icon = DSFImageManager.afpImage()
159 | case "ftp":
160 | self.icon = DSFImageManager.ftpImage()
161 | case "smb":
162 | self.icon = DSFImageManager.smbImage()
163 | case "vnc":
164 | self.icon = DSFImageManager.vncImage()
165 | default:
166 | self.icon = DSFImageManager.unknownImage()
167 | }
168 |
169 | self.didChangeValue(forKey: "icon")
170 | }
171 |
172 | func toDictionary() -> [String: Any]
173 | {
174 | var dict = ["address": self.address, "username": self.username]
175 | if self.guest
176 | {
177 | dict["guest"] = "yes"
178 | }
179 | return dict
180 | }
181 |
182 | static func fromDictionary(fileURL: URL, json: [String: Any]) -> DSFMountingYardItem?
183 | {
184 | let item = DSFMountingYardItem(
185 | url: fileURL,
186 | address: json["address"] as! String,
187 | username: json["username"] as! String,
188 | guest: json["guest"] != nil
189 | )
190 | return item
191 | }
192 |
193 | static func fromDictionary(json: [String: Any]) -> DSFMountingYardItem?
194 | {
195 | let item = DSFMountingYardItem()
196 | item.address = json["address"] as! String
197 | item.username = json["username"] as! String
198 | item.guest = json["guest"] != nil
199 | return item
200 | }
201 | }
202 |
--------------------------------------------------------------------------------
/Mounting Yard/NetFSShare.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NetFSShare.swift
3 | // Mounting Yard
4 | //
5 | // Created by Darren Ford on 31/7/18.
6 | // Copyright © 2018 Darren Ford. All rights reserved.
7 | //
8 | // https://gist.github.com/mosen/2ddf85824fbb5564aef527b60beb4669
9 | //
10 |
11 | import Foundation
12 | import NetFS
13 |
14 | enum ShareMountError: Error {
15 | case InvalidURL
16 | case MountpointInaccessible
17 | case InvalidMountOptions
18 | }
19 |
20 | enum MountOption {
21 | case NoBrowse
22 | case ReadOnly
23 | case AllowSubMounts
24 | case SoftMount
25 | case MountAtMountDirectory
26 |
27 | case Guest
28 | case AllowLoopback
29 | case NoAuthDialog
30 | case AllowAuthDialog
31 | case ForceAuthDialog
32 | }
33 |
34 | typealias NetFSMountCallback = (Int32, UnsafeMutableRawPointer?, CFArray?) -> Void
35 | typealias MountCallbackHandler = (Int32, URL?, [String]?) -> Void;
36 |
37 | protocol ShareDelegate {
38 | func shareWillMount(url: URL) -> Void
39 | func shareDidMount(url: URL, at paths: [String]?) -> Void
40 | func shareMountingDidFail(for url: URL, withError: Int32) -> Void
41 | }
42 |
43 | fileprivate func processOptionsForNetFS(options: [MountOption]) throws -> (NSMutableDictionary, NSMutableDictionary) {
44 | let openOptions: NSMutableDictionary = NSMutableDictionary()
45 | let mountOptions: NSMutableDictionary = NSMutableDictionary()
46 |
47 | for opt in options {
48 | switch opt {
49 |
50 | // mount_options
51 | case .NoBrowse:
52 | if let existingValue = mountOptions.value(forKey: kNetFSMountFlagsKey) {
53 | mountOptions[kNetFSMountFlagsKey] = existingValue as! Int32 | MNT_DONTBROWSE
54 | } else {
55 | mountOptions[kNetFSMountFlagsKey] = MNT_DONTBROWSE
56 | }
57 | case .ReadOnly:
58 | if let existingValue = mountOptions.value(forKey: kNetFSMountFlagsKey) {
59 | mountOptions[kNetFSMountFlagsKey] = existingValue as! Int32 | MNT_RDONLY
60 | } else {
61 | mountOptions[kNetFSMountFlagsKey] = MNT_RDONLY
62 | }
63 | case .AllowSubMounts:
64 | mountOptions[kNetFSAllowSubMountsKey] = true
65 | case .SoftMount:
66 | mountOptions[kNetFSSoftMountKey] = true
67 | case .MountAtMountDirectory:
68 | mountOptions[kNetFSMountAtMountDirKey] = true
69 |
70 | // open_options
71 | case .Guest:
72 | openOptions[kNetFSUseGuestKey] = true
73 | case .AllowLoopback:
74 | openOptions[kNetFSAllowLoopbackKey] = true
75 | case .NoAuthDialog:
76 | openOptions[kNAUIOptionKey] = kNAUIOptionNoUI
77 | case .AllowAuthDialog:
78 | openOptions[kNAUIOptionKey] = kNAUIOptionAllowUI
79 | case .ForceAuthDialog:
80 | openOptions[kNAUIOptionKey] = kNAUIOptionForceUI
81 | }
82 | }
83 |
84 | return (openOptions, mountOptions)
85 | }
86 |
87 |
88 | class Share {
89 | let url: URL
90 | var mountPoint: String = "/Volumes"
91 | var username: String?
92 | var password: String?
93 | fileprivate var asyncRequestId: AsyncRequestID?
94 | public var delegate: ShareDelegate?
95 |
96 | init(_ url: URL) {
97 | self.url = url
98 | }
99 |
100 | init(_ urlString: String) throws {
101 | guard let url = URL(string: urlString) else {
102 | throw ShareMountError.InvalidURL
103 | }
104 |
105 | self.url = url
106 | }
107 |
108 | public func cancelMounting() {
109 | NetFSMountURLCancel(self.asyncRequestId)
110 | }
111 |
112 | static func cancelMounting(id requestId: AsyncRequestID) {
113 | NetFSMountURLCancel(requestId)
114 | }
115 |
116 | public func mount() throws {
117 | let mountDirectoryURL = URL(fileURLWithPath: self.mountPoint)
118 | let operationQueue = OperationQueue.main
119 |
120 | let mountReportBlock: NetFSMountCallback = {
121 | status, asyncRequestId, mountedDirs in
122 |
123 | let mountedDirectories = mountedDirs as! [String]? ?? nil
124 |
125 | if (status != 0) {
126 | self.delegate?.shareMountingDidFail(for: self.url, withError: status)
127 | } else {
128 | self.delegate?.shareDidMount(url: self.url, at: mountedDirectories)
129 | }
130 | }
131 |
132 | NetFSMountURLAsync(url as CFURL,
133 | mountDirectoryURL as CFURL,
134 | username as CFString?,
135 | password as CFString?,
136 | nil,
137 | nil,
138 | &self.asyncRequestId,
139 | operationQueue.underlyingQueue,
140 | mountReportBlock)
141 | self.delegate?.shareWillMount(url: url)
142 | }
143 |
144 | public func mount(options: [MountOption]?, callbackHandler: @escaping MountCallbackHandler) throws -> AsyncRequestID? {
145 | let mountDirectoryURL = URL(fileURLWithPath: self.mountPoint)
146 | let operationQueue = OperationQueue.main
147 |
148 | let mountReportBlock: NetFSMountCallback = {
149 | (status, asyncRequestId, mountedDirs) in
150 | callbackHandler(status, self.url, mountedDirs as? [String])
151 | }
152 |
153 | var openOptions: NSMutableDictionary
154 | var mountOptions: NSMutableDictionary
155 |
156 | if options != nil {
157 | (openOptions, mountOptions) = try processOptionsForNetFS(options: options!)
158 | } else {
159 | openOptions = NSMutableDictionary()
160 | mountOptions = NSMutableDictionary()
161 | }
162 |
163 | NetFSMountURLAsync(url as CFURL,
164 | mountDirectoryURL as CFURL,
165 | username as CFString?,
166 | password as CFString?,
167 | openOptions as CFMutableDictionary,
168 | mountOptions as CFMutableDictionary,
169 | &self.asyncRequestId,
170 | operationQueue.underlyingQueue,
171 | mountReportBlock)
172 | self.delegate?.shareWillMount(url: url)
173 | return self.asyncRequestId
174 | }
175 | }
176 |
--------------------------------------------------------------------------------
/Mounting Yard/DSFMountingYardController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DSFMountingYardController.swift
3 | // Mounting Yard
4 | //
5 | // Created by Darren Ford on 31/7/18.
6 | // Copyright © 2018 Darren Ford. All rights reserved.
7 | //
8 |
9 | // MIT License
10 | //
11 | // Copyright (c) 2018 Darren Ford
12 | //
13 | // Permission is hereby granted, free of charge, to any person obtaining a copy
14 | // of this software and associated documentation files (the "Software"), to deal
15 | // in the Software without restriction, including without limitation the rights
16 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 | // copies of the Software, and to permit persons to whom the Software is
18 | // furnished to do so, subject to the following conditions:
19 | //
20 | // The above copyright notice and this permission notice shall be included in all
21 | // copies or substantial portions of the Software.
22 | //
23 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29 | // SOFTWARE.
30 |
31 | import Cocoa
32 | import NetFS
33 |
34 | @objc public class DSFMountingYardController: NSObject, NSUserNotificationCenterDelegate
35 | {
36 | lazy var filesLocation: URL = {
37 | var appSupport = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first
38 | appSupport!.appendPathComponent("Mounting Yard")
39 | try? FileManager.default.createDirectory(at: appSupport!, withIntermediateDirectories: false, attributes: nil)
40 | return appSupport!
41 | }()
42 |
43 | lazy var mountLocation: URL = {
44 | var userLoc = filesLocation
45 | userLoc.appendPathComponent("mounts")
46 | try? FileManager.default.createDirectory(at: userLoc, withIntermediateDirectories: false, attributes: nil)
47 | return userLoc
48 | }()
49 |
50 | let knownSchemes = Set(["smb", "afp", "cifs", "ftp"])
51 |
52 | // The urls which we successfully loaded from
53 | var managedUrls: [URL] = []
54 |
55 | @objc public dynamic var items: [DSFMountingYardItem] = []
56 |
57 | var activeRequests: [AsyncRequestID: DSFMountingYardItem] = [:]
58 |
59 | }
60 |
61 | // MARK: Loading and saving
62 |
63 | extension DSFMountingYardController
64 | {
65 | func load()
66 | {
67 | NSUserNotificationCenter.default.delegate = self
68 | do
69 | {
70 | if let fileURLs = try? FileManager.default.contentsOfDirectory(
71 | at: self.filesLocation,
72 | includingPropertiesForKeys: nil,
73 | options: [.skipsHiddenFiles, .skipsSubdirectoryDescendants]
74 | )
75 | {
76 | let filtered = fileURLs.filter { $0.pathExtension == "mountingYard" }
77 | for url in filtered
78 | {
79 | if let data = try? Data(contentsOf: url)
80 | {
81 | if let rawData = try? JSONSerialization.jsonObject(with: data, options: []),
82 | let json = rawData as? [String: Any]
83 | {
84 | if let item = DSFMountingYardItem.fromDictionary(fileURL: url, json: json)
85 | {
86 | self.managedUrls.append(url)
87 | self.items.append(item)
88 | }
89 | }
90 | }
91 | }
92 | }
93 | }
94 | }
95 |
96 | func openFile(filename: String) -> Bool
97 | {
98 | let url = URL(fileURLWithPath: filename)
99 | if url.pathExtension == "mountingYard"
100 | {
101 | let items = self.items.filter { $0.url == url }
102 | if items.count == 1
103 | {
104 | return self.mount(item: items.first!)
105 | }
106 | }
107 | return false
108 | }
109 |
110 | func save() -> Bool
111 | {
112 | // Make sure that the urls are synced
113 | for item in self.items
114 | {
115 | if item.url == nil
116 | {
117 | item.url = self.filesLocation.appendingPathComponent(item.name).appendingPathExtension("mountingYard")
118 | item.modified = true
119 | }
120 | }
121 |
122 | // Loop through the 'managed' urls (ie. the ones we loaded from)
123 | // and check to see if there's an item with the same url.
124 | // If there's not a matching url, then it has been deleted or renamed
125 | // We can remove it
126 | do
127 | {
128 | for url in self.managedUrls
129 | {
130 | let matching = self.items.filter { $0.url == url }
131 | if matching.count == 0
132 | {
133 | // This has been deleted or renamed. Remove the file
134 | try FileManager.default.removeItem(at: url)
135 | }
136 | }
137 | }
138 | catch
139 | {
140 | //
141 | }
142 |
143 | // Only sync the ones marked as modified
144 | let modifiedItems = self.items.filter { $0.modified == true }
145 | for item in modifiedItems
146 | {
147 | let dict = item.toDictionary()
148 | do
149 | {
150 | let data = try JSONSerialization.data(withJSONObject: dict, options: [.prettyPrinted])
151 | try data.write(to: item.url!)
152 | try FileManager.default.setAttributes(
153 | [FileAttributeKey.extensionHidden: NSNumber(value: true)],
154 | ofItemAtPath: item.url!.path
155 | )
156 | }
157 | catch
158 | {
159 | return false
160 | }
161 |
162 | item.modified = false
163 | }
164 | self.managedUrls = self.items.map { $0.url! }
165 |
166 | return true
167 | }
168 |
169 | func shareItems() -> Bool
170 | {
171 | let mySave = NSSavePanel()
172 | mySave.allowedFileTypes = ["mountingYardArchive"]
173 |
174 | mySave.begin { (result) -> Void in
175 | if result == NSApplication.ModalResponse.OK
176 | {
177 | _ = self.shareItems(to: mySave.url!)
178 | }
179 | }
180 | return true
181 | }
182 |
183 | private func shareItems(to url: URL) -> Bool
184 | {
185 | var exportData: [String: Any] = [:]
186 | for item in self.items
187 | {
188 | exportData[item.name] = item.toDictionary()
189 | }
190 | let data = try? JSONSerialization.data(withJSONObject: exportData, options: [.prettyPrinted])
191 | guard let outputJson = data else
192 | {
193 | return false
194 | }
195 |
196 | do
197 | {
198 | try outputJson.write(to: url)
199 |
200 | try FileManager.default.setAttributes(
201 | [FileAttributeKey.extensionHidden: NSNumber(value: true)],
202 | ofItemAtPath: url.path)
203 |
204 | return true
205 | }
206 | catch
207 | {
208 | return false
209 | }
210 | }
211 |
212 | func importItems() -> Bool
213 | {
214 | let myOpen = NSOpenPanel()
215 | myOpen.allowedFileTypes = ["mountingYardArchive"]
216 |
217 | myOpen.begin { (result) -> Void in
218 | if result == NSApplication.ModalResponse.OK
219 | {
220 | _ = self.importItems(from: myOpen.url!)
221 | }
222 | }
223 | return true
224 | }
225 |
226 | private func importItems(from url: URL) -> Bool
227 | {
228 | if let fileData = try? Data(contentsOf: url),
229 | let jsonData = try? JSONSerialization.jsonObject(with: fileData, options: []) as? [String: Any]
230 | {
231 | for readItem in jsonData!
232 | {
233 | if let itemData = readItem.value as? [String: Any],
234 | let item = DSFMountingYardItem.fromDictionary(json: itemData)
235 | {
236 | let itemName = readItem.key
237 | let matchingItems = self.items.filter { $0.name == itemName }
238 | if matchingItems.count == 0
239 | {
240 | item.name = itemName
241 | item.modified = true
242 | self.items.append(item)
243 | }
244 | }
245 | }
246 | }
247 | return true
248 | }
249 | }
250 |
251 | // MARK: Mounting items
252 |
253 | extension DSFMountingYardController
254 | {
255 | func mount(item: DSFMountingYardItem) -> Bool
256 | {
257 | if let mountPoint = item.validatedMountPoint()
258 | {
259 | // Already mounted! Just show it
260 | NSWorkspace.shared.activateFileViewerSelecting([mountPoint])
261 | return true
262 | }
263 |
264 | if self.activeRequests.filter( { $0.value == item }).count != 0
265 | {
266 | // Already in the process of making the connection
267 | return true
268 | }
269 |
270 | guard let url = URL(string: item.address),
271 | let scheme = url.scheme,
272 | !scheme.isEmpty else
273 | {
274 | // If we cant parse the URL, or the scheme is missing
275 | return false
276 | }
277 |
278 | if !self.knownSchemes.contains(scheme)
279 | {
280 | // If we don't know what the scheme is, just let the finder handle it
281 | return self.performMountUsingFinder(item: item)
282 | }
283 |
284 | return self.performMount(item: item, serverPath: url)
285 | }
286 |
287 | private func performMount(item: DSFMountingYardItem, serverPath: URL) -> Bool
288 | {
289 | var requestID: AsyncRequestID?
290 | let queue = DispatchQueue.main
291 |
292 | item.connecting = true
293 |
294 | var options: [String: Any]?
295 | if item.guest
296 | {
297 | options = [:]
298 | options![kNetFSUseGuestKey] = true
299 | }
300 |
301 | let result = NetFSMountURLAsync(
302 | serverPath as CFURL, self.mountLocation as CFURL,
303 | nil, nil,
304 | (options != nil) ? (options as! CFMutableDictionary) : nil,
305 | nil,
306 | &requestID,
307 | queue,
308 | self.performMountAsyncCallback())
309 |
310 | if result != 0
311 | {
312 | print("result: \(result)")
313 | return false
314 | }
315 | else
316 | {
317 | self.activeRequests[requestID!] = item
318 | }
319 | return true
320 | }
321 |
322 | private func performMountAsyncCallback() -> NetFSMountURLBlock
323 | {
324 | return { [weak self] (stat, requestId, mountpoints) in
325 |
326 | print("msg: \(stat) mountpoint: \(String(describing: mountpoints))")
327 |
328 | guard let blockSelf = self else
329 | {
330 | return
331 | }
332 |
333 | guard let item = blockSelf.activeRequests[requestId!] else
334 | {
335 | return
336 | }
337 | blockSelf.activeRequests.removeValue(forKey: requestId!)
338 |
339 | if (stat == 0)
340 | {
341 | item.connecting = false
342 | let pos = mountpoints as! [String]
343 | let urls = pos.map { URL(fileURLWithPath: $0) }
344 |
345 | item.mountedPoint = urls.first!
346 | blockSelf.showConnectionNotification(for: item)
347 |
348 | NSWorkspace.shared.activateFileViewerSelecting(urls)
349 | }
350 | }
351 | }
352 |
353 | private func performMountUsingFinder(item: DSFMountingYardItem) -> Bool
354 | {
355 | guard let url = URL(string: item.address) else
356 | {
357 | return false
358 | }
359 |
360 | var updatedURL = url
361 |
362 | // Put the name in the default 'user' location if they've specified one
363 | if !item.username.isEmpty, !item.guest,
364 | var urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: false)
365 | {
366 | urlComponents.user = item.username
367 | if let updated = urlComponents.url
368 | {
369 | updatedURL = updated
370 | }
371 | }
372 |
373 | return NSWorkspace.shared.open(updatedURL)
374 | }
375 | }
376 |
377 | // MARK: Notification handling
378 |
379 | extension DSFMountingYardController
380 | {
381 | func showConnectionNotification(for item: DSFMountingYardItem)
382 | {
383 | let notification = NSUserNotification()
384 | notification.title = NSLocalizedString("Remote server is connected", comment: "Notification message when server is successfully connected")
385 | notification.actionButtonTitle = "Show me"
386 | notification.hasActionButton = true
387 | notification.userInfo = ["mountPoint": item.mountedPoint!.path]
388 |
389 | let msg = String.localizedStringWithFormat(
390 | NSLocalizedString("The server ‘%@’ is now available", comment: "Descriptive message when server connects"),
391 | item.name
392 | )
393 | notification.informativeText = msg
394 | notification.soundName = NSUserNotificationDefaultSoundName
395 | NSUserNotificationCenter.default.deliver(notification)
396 | }
397 |
398 | public func userNotificationCenter(_: NSUserNotificationCenter, shouldPresent _: NSUserNotification) -> Bool
399 | {
400 | return true
401 | }
402 |
403 | public func userNotificationCenter(_: NSUserNotificationCenter, didActivate notification: NSUserNotification)
404 | {
405 | if let urlPath = notification.userInfo?["mountPoint"] as? String
406 | {
407 | let url = URL(fileURLWithPath: urlPath)
408 | NSWorkspace.shared.activateFileViewerSelecting([url])
409 | }
410 | }
411 | }
412 |
--------------------------------------------------------------------------------
/Mounting Yard.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 50;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 238AAED3210FC18B008F9E18 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 238AAED2210FC18B008F9E18 /* AppDelegate.swift */; };
11 | 238AAED5210FC18C008F9E18 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 238AAED4210FC18C008F9E18 /* Assets.xcassets */; };
12 | 238AAED8210FC18C008F9E18 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 238AAED6210FC18C008F9E18 /* MainMenu.xib */; };
13 | 238AAEE4210FC18C008F9E18 /* Mounting_PointTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 238AAEE3210FC18C008F9E18 /* Mounting_PointTests.swift */; };
14 | 238AAEF0210FC361008F9E18 /* DSFMountingYardStatusMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 238AAEEF210FC360008F9E18 /* DSFMountingYardStatusMenu.swift */; };
15 | 238AAEF3210FCBE4008F9E18 /* DSFMountingYardController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 238AAEF2210FCBE4008F9E18 /* DSFMountingYardController.swift */; };
16 | 238AAF07210FD7FE008F9E18 /* NetFS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 238AAF06210FD7FE008F9E18 /* NetFS.framework */; };
17 | 238AAF09210FF2BA008F9E18 /* DSFMountingYardItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 238AAF08210FF2BA008F9E18 /* DSFMountingYardItem.swift */; };
18 | 23AC1D2121141BC300531FCD /* DSFMountingYardSettingsWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 23AC1D1F21141BC300531FCD /* DSFMountingYardSettingsWindowController.swift */; };
19 | 23AC1D2221141BC300531FCD /* DSFMountingYardSettingsWindowController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 23AC1D2021141BC300531FCD /* DSFMountingYardSettingsWindowController.xib */; };
20 | 23AC1D242114603100531FCD /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 23AC1D232114603100531FCD /* Credits.rtf */; };
21 | 23D0131E211575B3009737FE /* DSFImageManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 23D0131D211575B3009737FE /* DSFImageManager.swift */; };
22 | /* End PBXBuildFile section */
23 |
24 | /* Begin PBXContainerItemProxy section */
25 | 238AAEE0210FC18C008F9E18 /* PBXContainerItemProxy */ = {
26 | isa = PBXContainerItemProxy;
27 | containerPortal = 238AAEC7210FC18B008F9E18 /* Project object */;
28 | proxyType = 1;
29 | remoteGlobalIDString = 238AAECE210FC18B008F9E18;
30 | remoteInfo = "Mounting Point";
31 | };
32 | /* End PBXContainerItemProxy section */
33 |
34 | /* Begin PBXCopyFilesBuildPhase section */
35 | 238AAF04210FD710008F9E18 /* Embed App Extensions */ = {
36 | isa = PBXCopyFilesBuildPhase;
37 | buildActionMask = 2147483647;
38 | dstPath = "";
39 | dstSubfolderSpec = 13;
40 | files = (
41 | );
42 | name = "Embed App Extensions";
43 | runOnlyForDeploymentPostprocessing = 0;
44 | };
45 | /* End PBXCopyFilesBuildPhase section */
46 |
47 | /* Begin PBXFileReference section */
48 | 23845BAC2128CF6A00B68382 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = SOURCE_ROOT; };
49 | 238AAECF210FC18B008F9E18 /* Mounting Yard.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Mounting Yard.app"; sourceTree = BUILT_PRODUCTS_DIR; };
50 | 238AAED2210FC18B008F9E18 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
51 | 238AAED4210FC18C008F9E18 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
52 | 238AAED7210FC18C008F9E18 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; };
53 | 238AAED9210FC18C008F9E18 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
54 | 238AAEDA210FC18C008F9E18 /* Mounting_Yard.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Mounting_Yard.entitlements; sourceTree = ""; };
55 | 238AAEDF210FC18C008F9E18 /* Mounting YardTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Mounting YardTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
56 | 238AAEE3210FC18C008F9E18 /* Mounting_PointTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Mounting_PointTests.swift; sourceTree = ""; };
57 | 238AAEE5210FC18C008F9E18 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
58 | 238AAEEF210FC360008F9E18 /* DSFMountingYardStatusMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DSFMountingYardStatusMenu.swift; sourceTree = ""; };
59 | 238AAEF1210FC801008F9E18 /* Mounting Yard.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "Mounting Yard.entitlements"; sourceTree = ""; };
60 | 238AAEF2210FCBE4008F9E18 /* DSFMountingYardController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DSFMountingYardController.swift; sourceTree = ""; };
61 | 238AAF06210FD7FE008F9E18 /* NetFS.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = NetFS.framework; path = System/Library/Frameworks/NetFS.framework; sourceTree = SDKROOT; };
62 | 238AAF08210FF2BA008F9E18 /* DSFMountingYardItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DSFMountingYardItem.swift; sourceTree = ""; };
63 | 23AC1D1F21141BC300531FCD /* DSFMountingYardSettingsWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DSFMountingYardSettingsWindowController.swift; sourceTree = ""; };
64 | 23AC1D2021141BC300531FCD /* DSFMountingYardSettingsWindowController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = DSFMountingYardSettingsWindowController.xib; sourceTree = ""; };
65 | 23AC1D232114603100531FCD /* Credits.rtf */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.rtf; path = Credits.rtf; sourceTree = ""; };
66 | 23D0131D211575B3009737FE /* DSFImageManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DSFImageManager.swift; sourceTree = ""; };
67 | /* End PBXFileReference section */
68 |
69 | /* Begin PBXFrameworksBuildPhase section */
70 | 238AAECC210FC18B008F9E18 /* Frameworks */ = {
71 | isa = PBXFrameworksBuildPhase;
72 | buildActionMask = 2147483647;
73 | files = (
74 | 238AAF07210FD7FE008F9E18 /* NetFS.framework in Frameworks */,
75 | );
76 | runOnlyForDeploymentPostprocessing = 0;
77 | };
78 | 238AAEDC210FC18C008F9E18 /* Frameworks */ = {
79 | isa = PBXFrameworksBuildPhase;
80 | buildActionMask = 2147483647;
81 | files = (
82 | );
83 | runOnlyForDeploymentPostprocessing = 0;
84 | };
85 | /* End PBXFrameworksBuildPhase section */
86 |
87 | /* Begin PBXGroup section */
88 | 238AAEC6210FC18B008F9E18 = {
89 | isa = PBXGroup;
90 | children = (
91 | 238AAED1210FC18B008F9E18 /* Mounting Yard */,
92 | 238AAEE2210FC18C008F9E18 /* Mounting PointTests */,
93 | 238AAED0210FC18B008F9E18 /* Products */,
94 | 238AAF05210FD7FE008F9E18 /* Frameworks */,
95 | );
96 | sourceTree = "";
97 | };
98 | 238AAED0210FC18B008F9E18 /* Products */ = {
99 | isa = PBXGroup;
100 | children = (
101 | 238AAECF210FC18B008F9E18 /* Mounting Yard.app */,
102 | 238AAEDF210FC18C008F9E18 /* Mounting YardTests.xctest */,
103 | );
104 | name = Products;
105 | sourceTree = "";
106 | };
107 | 238AAED1210FC18B008F9E18 /* Mounting Yard */ = {
108 | isa = PBXGroup;
109 | children = (
110 | 23A3F4DA2111838800D09510 /* Resources */,
111 | 238AAEF1210FC801008F9E18 /* Mounting Yard.entitlements */,
112 | 23845BAC2128CF6A00B68382 /* README.md */,
113 | 238AAED4210FC18C008F9E18 /* Assets.xcassets */,
114 | 238AAED6210FC18C008F9E18 /* MainMenu.xib */,
115 | 238AAED9210FC18C008F9E18 /* Info.plist */,
116 | 238AAEDA210FC18C008F9E18 /* Mounting_Yard.entitlements */,
117 | 238AAED2210FC18B008F9E18 /* AppDelegate.swift */,
118 | 238AAEEF210FC360008F9E18 /* DSFMountingYardStatusMenu.swift */,
119 | 238AAEF2210FCBE4008F9E18 /* DSFMountingYardController.swift */,
120 | 238AAF08210FF2BA008F9E18 /* DSFMountingYardItem.swift */,
121 | 23AC1D1F21141BC300531FCD /* DSFMountingYardSettingsWindowController.swift */,
122 | 23D0131D211575B3009737FE /* DSFImageManager.swift */,
123 | );
124 | path = "Mounting Yard";
125 | sourceTree = "";
126 | };
127 | 238AAEE2210FC18C008F9E18 /* Mounting PointTests */ = {
128 | isa = PBXGroup;
129 | children = (
130 | 238AAEE3210FC18C008F9E18 /* Mounting_PointTests.swift */,
131 | 238AAEE5210FC18C008F9E18 /* Info.plist */,
132 | );
133 | path = "Mounting PointTests";
134 | sourceTree = "";
135 | };
136 | 238AAF05210FD7FE008F9E18 /* Frameworks */ = {
137 | isa = PBXGroup;
138 | children = (
139 | 238AAF06210FD7FE008F9E18 /* NetFS.framework */,
140 | );
141 | name = Frameworks;
142 | sourceTree = "";
143 | };
144 | 23A3F4DA2111838800D09510 /* Resources */ = {
145 | isa = PBXGroup;
146 | children = (
147 | 23AC1D2021141BC300531FCD /* DSFMountingYardSettingsWindowController.xib */,
148 | 23AC1D232114603100531FCD /* Credits.rtf */,
149 | );
150 | path = Resources;
151 | sourceTree = "";
152 | };
153 | /* End PBXGroup section */
154 |
155 | /* Begin PBXNativeTarget section */
156 | 238AAECE210FC18B008F9E18 /* Mounting Yard */ = {
157 | isa = PBXNativeTarget;
158 | buildConfigurationList = 238AAEE8210FC18C008F9E18 /* Build configuration list for PBXNativeTarget "Mounting Yard" */;
159 | buildPhases = (
160 | 238AAECB210FC18B008F9E18 /* Sources */,
161 | 238AAECC210FC18B008F9E18 /* Frameworks */,
162 | 238AAECD210FC18B008F9E18 /* Resources */,
163 | 238AAF04210FD710008F9E18 /* Embed App Extensions */,
164 | );
165 | buildRules = (
166 | );
167 | dependencies = (
168 | );
169 | name = "Mounting Yard";
170 | productName = "Mounting Point";
171 | productReference = 238AAECF210FC18B008F9E18 /* Mounting Yard.app */;
172 | productType = "com.apple.product-type.application";
173 | };
174 | 238AAEDE210FC18C008F9E18 /* Mounting YardTests */ = {
175 | isa = PBXNativeTarget;
176 | buildConfigurationList = 238AAEEB210FC18C008F9E18 /* Build configuration list for PBXNativeTarget "Mounting YardTests" */;
177 | buildPhases = (
178 | 238AAEDB210FC18C008F9E18 /* Sources */,
179 | 238AAEDC210FC18C008F9E18 /* Frameworks */,
180 | 238AAEDD210FC18C008F9E18 /* Resources */,
181 | );
182 | buildRules = (
183 | );
184 | dependencies = (
185 | 238AAEE1210FC18C008F9E18 /* PBXTargetDependency */,
186 | );
187 | name = "Mounting YardTests";
188 | productName = "Mounting PointTests";
189 | productReference = 238AAEDF210FC18C008F9E18 /* Mounting YardTests.xctest */;
190 | productType = "com.apple.product-type.bundle.unit-test";
191 | };
192 | /* End PBXNativeTarget section */
193 |
194 | /* Begin PBXProject section */
195 | 238AAEC7210FC18B008F9E18 /* Project object */ = {
196 | isa = PBXProject;
197 | attributes = {
198 | LastSwiftUpdateCheck = 0940;
199 | LastUpgradeCheck = 0940;
200 | ORGANIZATIONNAME = "Darren Ford";
201 | TargetAttributes = {
202 | 238AAECE210FC18B008F9E18 = {
203 | CreatedOnToolsVersion = 9.4.1;
204 | SystemCapabilities = {
205 | com.apple.ApplicationGroups.Mac = {
206 | enabled = 0;
207 | };
208 | com.apple.Sandbox = {
209 | enabled = 1;
210 | };
211 | };
212 | };
213 | 238AAEDE210FC18C008F9E18 = {
214 | CreatedOnToolsVersion = 9.4.1;
215 | TestTargetID = 238AAECE210FC18B008F9E18;
216 | };
217 | };
218 | };
219 | buildConfigurationList = 238AAECA210FC18B008F9E18 /* Build configuration list for PBXProject "Mounting Yard" */;
220 | compatibilityVersion = "Xcode 9.3";
221 | developmentRegion = en;
222 | hasScannedForEncodings = 0;
223 | knownRegions = (
224 | en,
225 | Base,
226 | );
227 | mainGroup = 238AAEC6210FC18B008F9E18;
228 | productRefGroup = 238AAED0210FC18B008F9E18 /* Products */;
229 | projectDirPath = "";
230 | projectRoot = "";
231 | targets = (
232 | 238AAECE210FC18B008F9E18 /* Mounting Yard */,
233 | 238AAEDE210FC18C008F9E18 /* Mounting YardTests */,
234 | );
235 | };
236 | /* End PBXProject section */
237 |
238 | /* Begin PBXResourcesBuildPhase section */
239 | 238AAECD210FC18B008F9E18 /* Resources */ = {
240 | isa = PBXResourcesBuildPhase;
241 | buildActionMask = 2147483647;
242 | files = (
243 | 23AC1D242114603100531FCD /* Credits.rtf in Resources */,
244 | 238AAED5210FC18C008F9E18 /* Assets.xcassets in Resources */,
245 | 238AAED8210FC18C008F9E18 /* MainMenu.xib in Resources */,
246 | 23AC1D2221141BC300531FCD /* DSFMountingYardSettingsWindowController.xib in Resources */,
247 | );
248 | runOnlyForDeploymentPostprocessing = 0;
249 | };
250 | 238AAEDD210FC18C008F9E18 /* Resources */ = {
251 | isa = PBXResourcesBuildPhase;
252 | buildActionMask = 2147483647;
253 | files = (
254 | );
255 | runOnlyForDeploymentPostprocessing = 0;
256 | };
257 | /* End PBXResourcesBuildPhase section */
258 |
259 | /* Begin PBXSourcesBuildPhase section */
260 | 238AAECB210FC18B008F9E18 /* Sources */ = {
261 | isa = PBXSourcesBuildPhase;
262 | buildActionMask = 2147483647;
263 | files = (
264 | 23AC1D2121141BC300531FCD /* DSFMountingYardSettingsWindowController.swift in Sources */,
265 | 238AAEF0210FC361008F9E18 /* DSFMountingYardStatusMenu.swift in Sources */,
266 | 238AAF09210FF2BA008F9E18 /* DSFMountingYardItem.swift in Sources */,
267 | 23D0131E211575B3009737FE /* DSFImageManager.swift in Sources */,
268 | 238AAED3210FC18B008F9E18 /* AppDelegate.swift in Sources */,
269 | 238AAEF3210FCBE4008F9E18 /* DSFMountingYardController.swift in Sources */,
270 | );
271 | runOnlyForDeploymentPostprocessing = 0;
272 | };
273 | 238AAEDB210FC18C008F9E18 /* Sources */ = {
274 | isa = PBXSourcesBuildPhase;
275 | buildActionMask = 2147483647;
276 | files = (
277 | 238AAEE4210FC18C008F9E18 /* Mounting_PointTests.swift in Sources */,
278 | );
279 | runOnlyForDeploymentPostprocessing = 0;
280 | };
281 | /* End PBXSourcesBuildPhase section */
282 |
283 | /* Begin PBXTargetDependency section */
284 | 238AAEE1210FC18C008F9E18 /* PBXTargetDependency */ = {
285 | isa = PBXTargetDependency;
286 | target = 238AAECE210FC18B008F9E18 /* Mounting Yard */;
287 | targetProxy = 238AAEE0210FC18C008F9E18 /* PBXContainerItemProxy */;
288 | };
289 | /* End PBXTargetDependency section */
290 |
291 | /* Begin PBXVariantGroup section */
292 | 238AAED6210FC18C008F9E18 /* MainMenu.xib */ = {
293 | isa = PBXVariantGroup;
294 | children = (
295 | 238AAED7210FC18C008F9E18 /* Base */,
296 | );
297 | name = MainMenu.xib;
298 | sourceTree = "";
299 | };
300 | /* End PBXVariantGroup section */
301 |
302 | /* Begin XCBuildConfiguration section */
303 | 238AAEE6210FC18C008F9E18 /* Debug */ = {
304 | isa = XCBuildConfiguration;
305 | buildSettings = {
306 | ALWAYS_SEARCH_USER_PATHS = NO;
307 | CLANG_ANALYZER_NONNULL = YES;
308 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
309 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
310 | CLANG_CXX_LIBRARY = "libc++";
311 | CLANG_ENABLE_MODULES = YES;
312 | CLANG_ENABLE_OBJC_ARC = YES;
313 | CLANG_ENABLE_OBJC_WEAK = YES;
314 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
315 | CLANG_WARN_BOOL_CONVERSION = YES;
316 | CLANG_WARN_COMMA = YES;
317 | CLANG_WARN_CONSTANT_CONVERSION = YES;
318 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
319 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
320 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
321 | CLANG_WARN_EMPTY_BODY = YES;
322 | CLANG_WARN_ENUM_CONVERSION = YES;
323 | CLANG_WARN_INFINITE_RECURSION = YES;
324 | CLANG_WARN_INT_CONVERSION = YES;
325 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
326 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
327 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
328 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
329 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
330 | CLANG_WARN_STRICT_PROTOTYPES = YES;
331 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
332 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
333 | CLANG_WARN_UNREACHABLE_CODE = YES;
334 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
335 | CODE_SIGN_IDENTITY = "Mac Developer";
336 | COPY_PHASE_STRIP = NO;
337 | DEBUG_INFORMATION_FORMAT = dwarf;
338 | ENABLE_STRICT_OBJC_MSGSEND = YES;
339 | ENABLE_TESTABILITY = YES;
340 | GCC_C_LANGUAGE_STANDARD = gnu11;
341 | GCC_DYNAMIC_NO_PIC = NO;
342 | GCC_NO_COMMON_BLOCKS = YES;
343 | GCC_OPTIMIZATION_LEVEL = 0;
344 | GCC_PREPROCESSOR_DEFINITIONS = (
345 | "DEBUG=1",
346 | "$(inherited)",
347 | );
348 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
349 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
350 | GCC_WARN_UNDECLARED_SELECTOR = YES;
351 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
352 | GCC_WARN_UNUSED_FUNCTION = YES;
353 | GCC_WARN_UNUSED_VARIABLE = YES;
354 | MACOSX_DEPLOYMENT_TARGET = 10.10;
355 | MTL_ENABLE_DEBUG_INFO = YES;
356 | ONLY_ACTIVE_ARCH = YES;
357 | SDKROOT = macosx;
358 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
359 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
360 | };
361 | name = Debug;
362 | };
363 | 238AAEE7210FC18C008F9E18 /* Release */ = {
364 | isa = XCBuildConfiguration;
365 | buildSettings = {
366 | ALWAYS_SEARCH_USER_PATHS = NO;
367 | CLANG_ANALYZER_NONNULL = YES;
368 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
369 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
370 | CLANG_CXX_LIBRARY = "libc++";
371 | CLANG_ENABLE_MODULES = YES;
372 | CLANG_ENABLE_OBJC_ARC = YES;
373 | CLANG_ENABLE_OBJC_WEAK = YES;
374 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
375 | CLANG_WARN_BOOL_CONVERSION = YES;
376 | CLANG_WARN_COMMA = YES;
377 | CLANG_WARN_CONSTANT_CONVERSION = YES;
378 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
379 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
380 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
381 | CLANG_WARN_EMPTY_BODY = YES;
382 | CLANG_WARN_ENUM_CONVERSION = YES;
383 | CLANG_WARN_INFINITE_RECURSION = YES;
384 | CLANG_WARN_INT_CONVERSION = YES;
385 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
386 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
387 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
388 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
389 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
390 | CLANG_WARN_STRICT_PROTOTYPES = YES;
391 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
392 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
393 | CLANG_WARN_UNREACHABLE_CODE = YES;
394 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
395 | CODE_SIGN_IDENTITY = "Mac Developer";
396 | COPY_PHASE_STRIP = NO;
397 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
398 | ENABLE_NS_ASSERTIONS = NO;
399 | ENABLE_STRICT_OBJC_MSGSEND = YES;
400 | GCC_C_LANGUAGE_STANDARD = gnu11;
401 | GCC_NO_COMMON_BLOCKS = YES;
402 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
403 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
404 | GCC_WARN_UNDECLARED_SELECTOR = YES;
405 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
406 | GCC_WARN_UNUSED_FUNCTION = YES;
407 | GCC_WARN_UNUSED_VARIABLE = YES;
408 | MACOSX_DEPLOYMENT_TARGET = 10.10;
409 | MTL_ENABLE_DEBUG_INFO = NO;
410 | SDKROOT = macosx;
411 | SWIFT_COMPILATION_MODE = wholemodule;
412 | SWIFT_OPTIMIZATION_LEVEL = "-O";
413 | };
414 | name = Release;
415 | };
416 | 238AAEE9210FC18C008F9E18 /* Debug */ = {
417 | isa = XCBuildConfiguration;
418 | buildSettings = {
419 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
420 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
421 | CODE_SIGN_ENTITLEMENTS = "Mounting Yard/Mounting Yard.entitlements";
422 | CODE_SIGN_IDENTITY = "Mac Developer";
423 | CODE_SIGN_STYLE = Automatic;
424 | COMBINE_HIDPI_IMAGES = YES;
425 | DEVELOPMENT_TEAM = 3L6RK3LGGW;
426 | INFOPLIST_FILE = "$(SRCROOT)/Mounting Yard/Info.plist";
427 | LD_RUNPATH_SEARCH_PATHS = (
428 | "$(inherited)",
429 | "@executable_path/../Frameworks",
430 | );
431 | MACOSX_DEPLOYMENT_TARGET = 10.11;
432 | PRODUCT_BUNDLE_IDENTIFIER = "com.darrenford.Mounting-Yard";
433 | PRODUCT_NAME = "$(TARGET_NAME)";
434 | PROVISIONING_PROFILE = "";
435 | PROVISIONING_PROFILE_SPECIFIER = "";
436 | SWIFT_VERSION = 4.0;
437 | };
438 | name = Debug;
439 | };
440 | 238AAEEA210FC18C008F9E18 /* Release */ = {
441 | isa = XCBuildConfiguration;
442 | buildSettings = {
443 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
444 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
445 | CODE_SIGN_ENTITLEMENTS = "Mounting Yard/Mounting Yard.entitlements";
446 | CODE_SIGN_IDENTITY = "Mac Developer";
447 | CODE_SIGN_STYLE = Automatic;
448 | COMBINE_HIDPI_IMAGES = YES;
449 | DEVELOPMENT_TEAM = 3L6RK3LGGW;
450 | INFOPLIST_FILE = "$(SRCROOT)/Mounting Yard/Info.plist";
451 | LD_RUNPATH_SEARCH_PATHS = (
452 | "$(inherited)",
453 | "@executable_path/../Frameworks",
454 | );
455 | MACOSX_DEPLOYMENT_TARGET = 10.11;
456 | PRODUCT_BUNDLE_IDENTIFIER = "com.darrenford.Mounting-Yard";
457 | PRODUCT_NAME = "$(TARGET_NAME)";
458 | PROVISIONING_PROFILE = "";
459 | PROVISIONING_PROFILE_SPECIFIER = "";
460 | SWIFT_VERSION = 4.0;
461 | };
462 | name = Release;
463 | };
464 | 238AAEEC210FC18C008F9E18 /* Debug */ = {
465 | isa = XCBuildConfiguration;
466 | buildSettings = {
467 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
468 | BUNDLE_LOADER = "$(TEST_HOST)";
469 | CODE_SIGN_STYLE = Automatic;
470 | COMBINE_HIDPI_IMAGES = YES;
471 | DEVELOPMENT_TEAM = 3L6RK3LGGW;
472 | INFOPLIST_FILE = "Mounting PointTests/Info.plist";
473 | LD_RUNPATH_SEARCH_PATHS = (
474 | "$(inherited)",
475 | "@executable_path/../Frameworks",
476 | "@loader_path/../Frameworks",
477 | );
478 | PRODUCT_BUNDLE_IDENTIFIER = "com.darrenford.Mounting-PointTests";
479 | PRODUCT_NAME = "$(TARGET_NAME)";
480 | SWIFT_VERSION = 4.0;
481 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Mounting Yard.app/Contents/MacOS/Mounting Yard";
482 | };
483 | name = Debug;
484 | };
485 | 238AAEED210FC18C008F9E18 /* Release */ = {
486 | isa = XCBuildConfiguration;
487 | buildSettings = {
488 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
489 | BUNDLE_LOADER = "$(TEST_HOST)";
490 | CODE_SIGN_STYLE = Automatic;
491 | COMBINE_HIDPI_IMAGES = YES;
492 | DEVELOPMENT_TEAM = 3L6RK3LGGW;
493 | INFOPLIST_FILE = "Mounting PointTests/Info.plist";
494 | LD_RUNPATH_SEARCH_PATHS = (
495 | "$(inherited)",
496 | "@executable_path/../Frameworks",
497 | "@loader_path/../Frameworks",
498 | );
499 | PRODUCT_BUNDLE_IDENTIFIER = "com.darrenford.Mounting-PointTests";
500 | PRODUCT_NAME = "$(TARGET_NAME)";
501 | SWIFT_VERSION = 4.0;
502 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Mounting Yard.app/Contents/MacOS/Mounting Yard";
503 | };
504 | name = Release;
505 | };
506 | /* End XCBuildConfiguration section */
507 |
508 | /* Begin XCConfigurationList section */
509 | 238AAECA210FC18B008F9E18 /* Build configuration list for PBXProject "Mounting Yard" */ = {
510 | isa = XCConfigurationList;
511 | buildConfigurations = (
512 | 238AAEE6210FC18C008F9E18 /* Debug */,
513 | 238AAEE7210FC18C008F9E18 /* Release */,
514 | );
515 | defaultConfigurationIsVisible = 0;
516 | defaultConfigurationName = Release;
517 | };
518 | 238AAEE8210FC18C008F9E18 /* Build configuration list for PBXNativeTarget "Mounting Yard" */ = {
519 | isa = XCConfigurationList;
520 | buildConfigurations = (
521 | 238AAEE9210FC18C008F9E18 /* Debug */,
522 | 238AAEEA210FC18C008F9E18 /* Release */,
523 | );
524 | defaultConfigurationIsVisible = 0;
525 | defaultConfigurationName = Release;
526 | };
527 | 238AAEEB210FC18C008F9E18 /* Build configuration list for PBXNativeTarget "Mounting YardTests" */ = {
528 | isa = XCConfigurationList;
529 | buildConfigurations = (
530 | 238AAEEC210FC18C008F9E18 /* Debug */,
531 | 238AAEED210FC18C008F9E18 /* Release */,
532 | );
533 | defaultConfigurationIsVisible = 0;
534 | defaultConfigurationName = Release;
535 | };
536 | /* End XCConfigurationList section */
537 | };
538 | rootObject = 238AAEC7210FC18B008F9E18 /* Project object */;
539 | }
540 |
--------------------------------------------------------------------------------
/Mounting Yard/Resources/DSFMountingYardSettingsWindowController.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
178 |
189 |
190 |
191 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 | NSNegateBoolean
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |
330 |
331 |
332 |
333 |
334 |
335 |
336 |
337 |
338 |
349 |
350 |
351 |
352 |
353 |
354 |
355 |
356 |
357 |
358 |
359 |
360 |
361 |
362 |
363 |
364 |
365 |
366 |
367 |
368 |
369 |
370 |
371 |
372 |
373 |
374 |
375 |
376 |
377 |
378 |
379 |
380 |
381 |
382 |
383 |
384 |
385 |
386 |
387 |
388 |
389 |
390 |
391 |
392 |
393 |
394 |
395 |
396 |
397 |
398 |
399 |
400 |
401 |
402 |
403 |
404 |
405 |
406 |
407 |
408 |
409 |
410 |
411 |
412 |
413 |
414 |
415 |
416 |
417 |
418 |
419 |
420 |
421 |
422 |
423 |
424 |
425 |
426 |
427 |
447 |
448 |
449 |
450 |
451 |
452 |
453 |
454 |
455 |
456 |
--------------------------------------------------------------------------------
/Mounting Yard/Base.lproj/MainMenu.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
684 |
685 |
686 |
687 |
688 |
689 |
690 |
691 |
692 |
693 |
694 |
695 |
696 |
697 |
698 |
699 |
700 |
701 |
702 |
--------------------------------------------------------------------------------