Repository: Codeux/Textual
Branch: master
Commit: 243a6e2c06ad
Files: 910
Total size: 7.4 MB
Directory structure:
gitextract_u26s7vme/
├── .gitignore
├── .gitmodules
├── Common/
│ ├── Documents/
│ │ └── Acknowledgements.docx
│ └── Release DMG.dmgCanvas/
│ └── Disk Image
├── Configurations/
│ ├── Build/
│ │ ├── Code Signing Identity.xcconfig
│ │ ├── Common/
│ │ │ ├── Foundation Debug.xcconfig
│ │ │ ├── Foundation.xcconfig
│ │ │ ├── Preserve Symbols.xcconfig
│ │ │ ├── Textual App.xcconfig
│ │ │ ├── Textual Extensions.xcconfig
│ │ │ ├── Textual.xcconfig
│ │ │ ├── XPC Service - ICL Extensions.xcconfig
│ │ │ ├── XPC Service - ICL.xcconfig
│ │ │ └── XPC Services.xcconfig
│ │ ├── Debug/
│ │ │ ├── Enabled Features.xcconfig
│ │ │ ├── Textual App.xcconfig
│ │ │ ├── Textual Extensions.xcconfig
│ │ │ ├── Textual.xcconfig
│ │ │ ├── XPC Service - ICL Extensions.xcconfig
│ │ │ ├── XPC Service - ICL.xcconfig
│ │ │ └── XPC Services.xcconfig
│ │ ├── README.md
│ │ └── Standard Release/
│ │ ├── Enabled Features.xcconfig
│ │ ├── Textual App.xcconfig
│ │ ├── Textual Extensions.xcconfig
│ │ ├── Textual.xcconfig
│ │ ├── XPC Service - ICL Extensions.xcconfig
│ │ ├── XPC Service - ICL.xcconfig
│ │ └── XPC Services.xcconfig
│ ├── ExportArchiveConfiguration.plist
│ └── Sandbox/
│ └── Inherited.entitlements
├── README.md
├── Sources/
│ ├── App/
│ │ ├── Build Scripts/
│ │ │ ├── BuildExtensions.sh
│ │ │ ├── BuildFrameworks.sh
│ │ │ ├── BuildServices.sh
│ │ │ ├── ExportArchive.sh
│ │ │ ├── MergeSwift.sh
│ │ │ ├── PostprocessSparkle.sh
│ │ │ ├── UpdateFeatureFlags.sh
│ │ │ └── UpdateVersionInfo.sh
│ │ ├── Classes/
│ │ │ ├── Controllers/
│ │ │ │ ├── TXAppearance.m
│ │ │ │ ├── TXApplication.m
│ │ │ │ ├── TXGlobalModels.m
│ │ │ │ ├── TXMasterController.m
│ │ │ │ ├── TXMenuController.m
│ │ │ │ ├── TXSharedApplication.m
│ │ │ │ └── TXWindowController.m
│ │ │ ├── Dialogs/
│ │ │ │ ├── Channel Spotlight/
│ │ │ │ │ ├── TDCChannelSpotlightAppearance.m
│ │ │ │ │ ├── TDCChannelSpotlightController.m
│ │ │ │ │ ├── TDCChannelSpotlightControls.m
│ │ │ │ │ ├── TDCChannelSpotlightSearchResult.m
│ │ │ │ │ └── TDCChannelSpotlightSearchResultsTable.m
│ │ │ │ ├── File Transfers/
│ │ │ │ │ ├── TDCFileTransferDialog.m
│ │ │ │ │ ├── TDCFileTransferDialogTableCell.m
│ │ │ │ │ └── TDCFileTransferDialogTransferController.m
│ │ │ │ ├── License Manager/
│ │ │ │ │ └── Standalone/
│ │ │ │ │ ├── TDCLicenseManagerDialog.m
│ │ │ │ │ ├── TDCLicenseManagerMigrateAppStoreSheet.m
│ │ │ │ │ ├── TDCLicenseManagerRecoverLostLicenseSheet.m
│ │ │ │ │ ├── TDCLicenseUpgradeActivateSheet.m
│ │ │ │ │ ├── TDCLicenseUpgradeCommonActions.m
│ │ │ │ │ ├── TDCLicenseUpgradeDialog.m
│ │ │ │ │ └── TDCLicenseUpgradeEligibilitySheet.m
│ │ │ │ ├── Preferences/
│ │ │ │ │ ├── TDCPreferencesController.m
│ │ │ │ │ ├── TDCPreferencesNotificationConfiguration.m
│ │ │ │ │ └── TDCPreferencesUserStyleSheet.m
│ │ │ │ ├── Server Endpoint/
│ │ │ │ │ ├── TDCServerEndpointListSheet.m
│ │ │ │ │ └── TDCServerEndpointListSheetTable.m
│ │ │ │ ├── TDCAboutDialog.m
│ │ │ │ ├── TDCAddressBookSheet.m
│ │ │ │ ├── TDCAlert.m
│ │ │ │ ├── TDCChannelBanListSheet.m
│ │ │ │ ├── TDCChannelInviteSheet.m
│ │ │ │ ├── TDCChannelModifyModesSheet.m
│ │ │ │ ├── TDCChannelModifyTopicSheet.m
│ │ │ │ ├── TDCChannelPropertiesNotificationConfiguration.m
│ │ │ │ ├── TDCChannelPropertiesSheet.m
│ │ │ │ ├── TDCHighlightEntrySheet.m
│ │ │ │ ├── TDCInputPrompt.m
│ │ │ │ ├── TDCNicknameColorSheet.m
│ │ │ │ ├── TDCProgressIndicatorSheet.m
│ │ │ │ ├── TDCServerChangeNicknameSheet.m
│ │ │ │ ├── TDCServerChannelListDialog.m
│ │ │ │ ├── TDCServerHighlightListSheet.m
│ │ │ │ ├── TDCServerPropertiesSheet.m
│ │ │ │ ├── TDCSheetBase.m
│ │ │ │ ├── TDCWelcomeSheet.m
│ │ │ │ └── TDCWindowBase.m
│ │ │ ├── Headers/
│ │ │ │ ├── External Libraries/
│ │ │ │ │ ├── GTMEncodeHTML.h
│ │ │ │ │ └── OELReachability.h
│ │ │ │ ├── IRC.h
│ │ │ │ ├── IRCAddressBook.h
│ │ │ │ ├── IRCAddressBookUserTracking.h
│ │ │ │ ├── IRCChannel.h
│ │ │ │ ├── IRCChannelConfig.h
│ │ │ │ ├── IRCChannelMemberList.h
│ │ │ │ ├── IRCChannelMode.h
│ │ │ │ ├── IRCChannelUser.h
│ │ │ │ ├── IRCClient.h
│ │ │ │ ├── IRCClientConfig.h
│ │ │ │ ├── IRCColorFormat.h
│ │ │ │ ├── IRCCommandIndex.h
│ │ │ │ ├── IRCConnection.h
│ │ │ │ ├── IRCHighlightLogEntry.h
│ │ │ │ ├── IRCHighlightMatchCondition.h
│ │ │ │ ├── IRCISupportInfo.h
│ │ │ │ ├── IRCMessage.h
│ │ │ │ ├── IRCModeInfo.h
│ │ │ │ ├── IRCNetworkList.h
│ │ │ │ ├── IRCNumerics.h
│ │ │ │ ├── IRCPrefix.h
│ │ │ │ ├── IRCSendingMessage.h
│ │ │ │ ├── IRCServer.h
│ │ │ │ ├── IRCTreeItem.h
│ │ │ │ ├── IRCUser.h
│ │ │ │ ├── IRCUserRelations.h
│ │ │ │ ├── IRCWorld.h
│ │ │ │ ├── Internal/
│ │ │ │ │ ├── IRCAddressBookInternal.h
│ │ │ │ │ ├── IRCChannelConfigInternal.h
│ │ │ │ │ ├── IRCChannelUserInternal.h
│ │ │ │ │ ├── IRCClientConfigInternal.h
│ │ │ │ │ ├── IRCHighlightLogEntryInternal.h
│ │ │ │ │ ├── IRCHighlightMatchConditionInternal.h
│ │ │ │ │ ├── IRCMessageInternal.h
│ │ │ │ │ ├── IRCModeInfoInternal.h
│ │ │ │ │ ├── IRCPrefixInternal.h
│ │ │ │ │ ├── IRCServerInternal.h
│ │ │ │ │ ├── IRCUserInternal.h
│ │ │ │ │ ├── TDCChannelPropertiesSheetInternal.h
│ │ │ │ │ ├── TDCChannelSpotlightAppearanceInternal.h
│ │ │ │ │ ├── TDCChannelSpotlightControllerInternal.h
│ │ │ │ │ ├── TDCFileTransferDialogInternal.h
│ │ │ │ │ └── TVCLogLineInternal.h
│ │ │ │ ├── NSColorHelper.h
│ │ │ │ ├── NSStringHelper.h
│ │ │ │ ├── NSViewHelper.h
│ │ │ │ ├── Private/
│ │ │ │ │ ├── ICLPayloadLocalPrivate.h
│ │ │ │ │ ├── IRCAddressBookMatchCachePrivate.h
│ │ │ │ │ ├── IRCAddressBookUserTrackingPrivate.h
│ │ │ │ │ ├── IRCChannelConfigPrivate.h
│ │ │ │ │ ├── IRCChannelMemberListControllerPrivate.h
│ │ │ │ │ ├── IRCChannelMemberListPrivate.h
│ │ │ │ │ ├── IRCChannelModePrivate.h
│ │ │ │ │ ├── IRCChannelPrivate.h
│ │ │ │ │ ├── IRCChannelUserPrivate.h
│ │ │ │ │ ├── IRCClientConfigPrivate.h
│ │ │ │ │ ├── IRCClientPrivate.h
│ │ │ │ │ ├── IRCClientRequestedCommandsPrivate.h
│ │ │ │ │ ├── IRCColorFormatPrivate.h
│ │ │ │ │ ├── IRCCommandIndexPrivate.h
│ │ │ │ │ ├── IRCConnectionPrivate.h
│ │ │ │ │ ├── IRCExtrasPrivate.h
│ │ │ │ │ ├── IRCHighlightLogEntryPrivate.h
│ │ │ │ │ ├── IRCISupportInfoPrivate.h
│ │ │ │ │ ├── IRCMessageBatchPrivate.h
│ │ │ │ │ ├── IRCMessagePrivate.h
│ │ │ │ │ ├── IRCServerPrivate.h
│ │ │ │ │ ├── IRCTimerCommandPrivate.h
│ │ │ │ │ ├── IRCTreeItemPrivate.h
│ │ │ │ │ ├── IRCUserNicknameColorStyleGeneratorPrivate.h
│ │ │ │ │ ├── IRCUserPersistentStorePrivate.h
│ │ │ │ │ ├── IRCUserPrivate.h
│ │ │ │ │ ├── IRCUserRelationsPrivate.h
│ │ │ │ │ ├── IRCWorldPrivate.h
│ │ │ │ │ ├── NSTableVIewHelperPrivate.h
│ │ │ │ │ ├── NSViewHelperPrivate.h
│ │ │ │ │ ├── SwiftBridgingHeaderPrivate.h
│ │ │ │ │ ├── TDCAboutDialogPrivate.h
│ │ │ │ │ ├── TDCAddressBookSheetPrivate.h
│ │ │ │ │ ├── TDCChannelBanListSheetPrivate.h
│ │ │ │ │ ├── TDCChannelInviteSheetPrivate.h
│ │ │ │ │ ├── TDCChannelModifyModesSheetPrivate.h
│ │ │ │ │ ├── TDCChannelModifyTopicSheetPrivate.h
│ │ │ │ │ ├── TDCChannelPropertiesNotificationConfigurationPrivate.h
│ │ │ │ │ ├── TDCChannelPropertiesSheetPrivate.h
│ │ │ │ │ ├── TDCChannelSpotlightAppearancePrivate.h
│ │ │ │ │ ├── TDCChannelSpotlightControllerPrivate.h
│ │ │ │ │ ├── TDCChannelSpotlightControlsPrivate.h
│ │ │ │ │ ├── TDCChannelSpotlightSearchResultPrivate.h
│ │ │ │ │ ├── TDCChannelSpotlightSearchResultsTablePrivate.h
│ │ │ │ │ ├── TDCFileTransferDialogPrivate.h
│ │ │ │ │ ├── TDCFileTransferDialogTableCellPrivate.h
│ │ │ │ │ ├── TDCFileTransferDialogTransferControllerPrivate.h
│ │ │ │ │ ├── TDCHighlightEntrySheetPrivate.h
│ │ │ │ │ ├── TDCLicenseManagerDialogPrivate.h
│ │ │ │ │ ├── TDCLicenseManagerMigrateAppStoreSheetPrivate.h
│ │ │ │ │ ├── TDCLicenseManagerRecoverLostLicenseSheetPrivate.h
│ │ │ │ │ ├── TDCLicenseUpgradeActivateSheetPrivate.h
│ │ │ │ │ ├── TDCLicenseUpgradeCommonActionsPrivate.h
│ │ │ │ │ ├── TDCLicenseUpgradeDialogPrivate.h
│ │ │ │ │ ├── TDCLicenseUpgradeEligibilitySheetPrivate.h
│ │ │ │ │ ├── TDCNicknameColorSheetPrivate.h
│ │ │ │ │ ├── TDCPreferencesControllerPrivate.h
│ │ │ │ │ ├── TDCPreferencesNotificationConfigurationPrivate.h
│ │ │ │ │ ├── TDCPreferencesUserStyleSheetPrivate.h
│ │ │ │ │ ├── TDCProgressIndicatorSheetPrivate.h
│ │ │ │ │ ├── TDCServerChangeNicknameSheetPrivate.h
│ │ │ │ │ ├── TDCServerChannelListDialogPrivate.h
│ │ │ │ │ ├── TDCServerEndpointListSheetPrivate.h
│ │ │ │ │ ├── TDCServerEndpointListSheetTablePrivate.h
│ │ │ │ │ ├── TDCServerHighlightListSheetPrivate.h
│ │ │ │ │ ├── TDCServerPropertiesSheetPrivate.h
│ │ │ │ │ ├── TDCSharedProtocolDefinitionsPrivate.h
│ │ │ │ │ ├── TDCWelcomeSheetPrivate.h
│ │ │ │ │ ├── THOPluginDispatcherPrivate.h
│ │ │ │ │ ├── THOPluginItemPrivate.h
│ │ │ │ │ ├── THOPluginManagerPrivate.h
│ │ │ │ │ ├── THOPluginProtocolPrivate.h
│ │ │ │ │ ├── TLOEncryptionManagerPrivate.h
│ │ │ │ │ ├── TLOFileLoggerPrivate.h
│ │ │ │ │ ├── TLOInputHistoryPrivate.h
│ │ │ │ │ ├── TLOLicenseManagerDownloaderPrivate.h
│ │ │ │ │ ├── TLOLicenseManagerLastGenPrivate.h
│ │ │ │ │ ├── TLOLicenseManagerPrivate.h
│ │ │ │ │ ├── TLONicknameCompletionStatusPrivate.h
│ │ │ │ │ ├── TLONotificationConfigurationPrivate.h
│ │ │ │ │ ├── TLONotificationControllerPrivate.h
│ │ │ │ │ ├── TLOSpeechSynthesizerPrivate.h
│ │ │ │ │ ├── TLOSpokenNotificationPrivate.h
│ │ │ │ │ ├── TPCApplicationInfoPrivate.h
│ │ │ │ │ ├── TPCPathInfoPrivate.h
│ │ │ │ │ ├── TPCPreferencesImportExportPrivate.h
│ │ │ │ │ ├── TPCPreferencesLocalPrivate.h
│ │ │ │ │ ├── TPCResourceManagerPrivate.h
│ │ │ │ │ ├── TPCSandboxMigrationPrivate.h
│ │ │ │ │ ├── TPCThemeControllerPrivate.h
│ │ │ │ │ ├── TPCThemePrivate.h
│ │ │ │ │ ├── TVCAppearancePrivate.h
│ │ │ │ │ ├── TVCChannelSelectionOutlineViewCellPrivate.h
│ │ │ │ │ ├── TVCChannelSelectionViewControllerPrivate.h
│ │ │ │ │ ├── TVCContentNavigationOutlineViewPrivate.h
│ │ │ │ │ ├── TVCDockIconPrivate.h
│ │ │ │ │ ├── TVCErrorMessagePopoverControllerPrivate.h
│ │ │ │ │ ├── TVCErrorMessagePopoverPrivate.h
│ │ │ │ │ ├── TVCLogControllerHistoricLogFilePrivate.h
│ │ │ │ │ ├── TVCLogControllerInlineMediaServicePrivate.h
│ │ │ │ │ ├── TVCLogControllerOperationQueuePrivate.h
│ │ │ │ │ ├── TVCLogControllerPrivate.h
│ │ │ │ │ ├── TVCLogLinePrivate.h
│ │ │ │ │ ├── TVCLogPolicyPrivate.h
│ │ │ │ │ ├── TVCLogScriptEventSinkPrivate.h
│ │ │ │ │ ├── TVCLogViewInternalWK1.h
│ │ │ │ │ ├── TVCLogViewInternalWK2.h
│ │ │ │ │ ├── TVCLogViewPrivate.h
│ │ │ │ │ ├── TVCMainWindowAppearancePrivate.h
│ │ │ │ │ ├── TVCMainWindowChannelViewPrivate.h
│ │ │ │ │ ├── TVCMainWindowLoadingScreenPrivate.h
│ │ │ │ │ ├── TVCMainWindowPrivate.h
│ │ │ │ │ ├── TVCMainWindowSegmentedControlPrivate.h
│ │ │ │ │ ├── TVCMainWindowSplitViewPrivate.h
│ │ │ │ │ ├── TVCMainWindowTextViewAppearancePrivate.h
│ │ │ │ │ ├── TVCMainWindowTextViewPrivate.h
│ │ │ │ │ ├── TVCMainWindowTitlebarAccessoryViewPrivate.h
│ │ │ │ │ ├── TVCMemberListAppearancePrivate.h
│ │ │ │ │ ├── TVCMemberListCellPrivate.h
│ │ │ │ │ ├── TVCMemberListPrivate.h
│ │ │ │ │ ├── TVCMemberListUserInfoPopoverPrivate.h
│ │ │ │ │ ├── TVCNotificationConfigurationViewControllerPrivate.h
│ │ │ │ │ ├── TVCServerListAppearancePrivate.h
│ │ │ │ │ ├── TVCServerListCellPrivate.h
│ │ │ │ │ ├── TVCServerListPrivate.h
│ │ │ │ │ ├── TVCTextFormatterMenuPrivate.h
│ │ │ │ │ ├── TVCTextViewWithIRCFormatterPrivate.h
│ │ │ │ │ ├── TVCWK1AutoScrollerPrivate.h
│ │ │ │ │ ├── TXAppearancePrivate.h
│ │ │ │ │ ├── TXApplicationPrivate.h
│ │ │ │ │ ├── TXGlobalModelsPrivate.h
│ │ │ │ │ ├── TXMasterControllerPrivate.h
│ │ │ │ │ ├── TXMenuControllerPrivate.h
│ │ │ │ │ ├── TXSharedApplicationPrivate.h
│ │ │ │ │ ├── TXWindowControllerPrivate.h
│ │ │ │ │ ├── TextualPrivate.h
│ │ │ │ │ ├── WKWebViewPrivate.h
│ │ │ │ │ └── WebScriptObjectHelperPrivate.h
│ │ │ │ ├── TDCAlert.h
│ │ │ │ ├── TDCInputPrompt.h
│ │ │ │ ├── TDCSheetBase.h
│ │ │ │ ├── TDCWindowBase.h
│ │ │ │ ├── THOPluginManager.h
│ │ │ │ ├── THOPluginProtocol.h
│ │ │ │ ├── THOUnicodeHelper.h
│ │ │ │ ├── TLOEncryptionManager.h
│ │ │ │ ├── TLOInternetAddressLookup.h
│ │ │ │ ├── TLOKeyEventHandler.h
│ │ │ │ ├── TLOLinkParser.h
│ │ │ │ ├── TLONotificationController.h
│ │ │ │ ├── TLOSoundPlayer.h
│ │ │ │ ├── TLOpenLink.h
│ │ │ │ ├── TPCApplicationInfo.h
│ │ │ │ ├── TPCPathInfo.h
│ │ │ │ ├── TPCPreferencesImportExport.h
│ │ │ │ ├── TPCPreferencesLocal.h
│ │ │ │ ├── TPCPreferencesReload.h
│ │ │ │ ├── TPCPreferencesUserDefaultsLocal.h
│ │ │ │ ├── TPCResourceManager.h
│ │ │ │ ├── TPCTheme.h
│ │ │ │ ├── TPCThemeController.h
│ │ │ │ ├── TVCAlert.h
│ │ │ │ ├── TVCAppearance.h
│ │ │ │ ├── TVCAutoExpandingTextField.h
│ │ │ │ ├── TVCAutoExpandingTokenField.h
│ │ │ │ ├── TVCBasicTableView.h
│ │ │ │ ├── TVCChannelSelectionViewController.h
│ │ │ │ ├── TVCLogController.h
│ │ │ │ ├── TVCLogLine.h
│ │ │ │ ├── TVCLogRenderer.h
│ │ │ │ ├── TVCLogView.h
│ │ │ │ ├── TVCMainWindow.h
│ │ │ │ ├── TVCMainWindowAppearance.h
│ │ │ │ ├── TVCMainWindowLoadingScreen.h
│ │ │ │ ├── TVCMainWindowSplitView.h
│ │ │ │ ├── TVCMainWindowTextView.h
│ │ │ │ ├── TVCMainWindowTextViewAppearance.h
│ │ │ │ ├── TVCMemberList.h
│ │ │ │ ├── TVCMemberListAppearance.h
│ │ │ │ ├── TVCServerList.h
│ │ │ │ ├── TVCServerListAppearance.h
│ │ │ │ ├── TVCTextViewWithIRCFormatter.h
│ │ │ │ ├── TVCValidatedComboBox.h
│ │ │ │ ├── TVCValidatedTextField.h
│ │ │ │ ├── TXAppearance.h
│ │ │ │ ├── TXAppearanceHelper.h
│ │ │ │ ├── TXGlobalModels.h
│ │ │ │ ├── TXMasterController.h
│ │ │ │ ├── TXMenuController.h
│ │ │ │ ├── TXSharedApplication.h
│ │ │ │ ├── Textual.h
│ │ │ │ └── TextualApplication.h
│ │ │ ├── Helpers/
│ │ │ │ ├── Cocoa (Objective-C)/
│ │ │ │ │ ├── NSColorHelper.m
│ │ │ │ │ ├── NSStringHelper.m
│ │ │ │ │ ├── NSTableViewHelper.m
│ │ │ │ │ ├── NSViewHelper.m
│ │ │ │ │ └── TXAppearanceHelper.m
│ │ │ │ ├── External Libraries/
│ │ │ │ │ ├── Google/
│ │ │ │ │ │ └── GTMEncodeHTML.m
│ │ │ │ │ └── WebKit/
│ │ │ │ │ └── WebScriptObjectHelper.m
│ │ │ │ ├── Plugin Architecture/
│ │ │ │ │ ├── THOPluginDispatcher.m
│ │ │ │ │ ├── THOPluginItem.m
│ │ │ │ │ ├── THOPluginItemLogging.m
│ │ │ │ │ └── THOPluginManager.m
│ │ │ │ └── THOUnicodeHelper.m
│ │ │ ├── IRC/
│ │ │ │ ├── IRCAddressBook.m
│ │ │ │ ├── IRCAddressBookMatchCache.m
│ │ │ │ ├── IRCAddressBookUserTracking.m
│ │ │ │ ├── IRCChannel.m
│ │ │ │ ├── IRCChannelConfig.m
│ │ │ │ ├── IRCChannelMemberList.m
│ │ │ │ ├── IRCChannelMemberListController.m
│ │ │ │ ├── IRCChannelMode.m
│ │ │ │ ├── IRCClient.m
│ │ │ │ ├── IRCClientConfig.m
│ │ │ │ ├── IRCClientRequestedCommands.m
│ │ │ │ ├── IRCCommandIndex.m
│ │ │ │ ├── IRCConnection.m
│ │ │ │ ├── IRCExtras.m
│ │ │ │ ├── IRCHighlightLogEntry.m
│ │ │ │ ├── IRCHighlightMatchCondition.m
│ │ │ │ ├── IRCISupportInfo.m
│ │ │ │ ├── IRCMessage.m
│ │ │ │ ├── IRCMessageBatch.m
│ │ │ │ ├── IRCModeInfo.m
│ │ │ │ ├── IRCNetworkList.m
│ │ │ │ ├── IRCPrefix.m
│ │ │ │ ├── IRCSendingMessage.m
│ │ │ │ ├── IRCServer.m
│ │ │ │ ├── IRCTimerCommand.m
│ │ │ │ ├── IRCTreeItem.m
│ │ │ │ ├── IRCWorld.m
│ │ │ │ └── Users/
│ │ │ │ ├── IRCChannelUser.m
│ │ │ │ ├── IRCUser.m
│ │ │ │ ├── IRCUserNicknameColorStyleGenerator.m
│ │ │ │ ├── IRCUserPersistentStore.m
│ │ │ │ └── IRCUserRelations.m
│ │ │ ├── Library/
│ │ │ │ ├── Color Formatting/
│ │ │ │ │ └── IRCColorFormat.m
│ │ │ │ ├── External Libraries/
│ │ │ │ │ └── Sockets/
│ │ │ │ │ └── OELReachability.m
│ │ │ │ ├── License Manager/
│ │ │ │ │ └── Standalone/
│ │ │ │ │ ├── TLOLicenseManager.m
│ │ │ │ │ ├── TLOLicenseManagerDownloader.m
│ │ │ │ │ └── TLOLicenseManagerLastGen.m
│ │ │ │ ├── TLOEncryptionManager.m
│ │ │ │ ├── TLOFileLogger.m
│ │ │ │ ├── TLOInputHistory.m
│ │ │ │ ├── TLOInternetAddressLookup.m
│ │ │ │ ├── TLOKeyEventHandler.m
│ │ │ │ ├── TLOLinkParser.swift
│ │ │ │ ├── TLONicknameCompletionStatus.m
│ │ │ │ ├── TLONotificationConfiguration.m
│ │ │ │ ├── TLONotificationController.m
│ │ │ │ ├── TLOSoundPlayer.m
│ │ │ │ ├── TLOSpeechSynthesizer.m
│ │ │ │ ├── TLOSpokenNotification.m
│ │ │ │ └── TLOpenLink.swift
│ │ │ ├── Others/
│ │ │ │ └── main.m
│ │ │ ├── Preferences/
│ │ │ │ ├── TPCApplicationInfo.m
│ │ │ │ ├── TPCPathInfo.m
│ │ │ │ ├── TPCPreferencesImportExport.m
│ │ │ │ ├── TPCPreferencesLocal.m
│ │ │ │ ├── TPCPreferencesReload.m
│ │ │ │ ├── TPCPreferencesUserDefaultsLocal.m
│ │ │ │ ├── TPCResourceManager.m
│ │ │ │ ├── TPCSandboxMigration.m
│ │ │ │ └── Themes/
│ │ │ │ ├── TPCTheme.m
│ │ │ │ └── TPCThemeController.m
│ │ │ ├── Services/
│ │ │ │ └── ICLPayloadLocal.m
│ │ │ └── Views/
│ │ │ ├── Channel Selection Table/
│ │ │ │ ├── TVCChannelSelectionOutlineCellView.m
│ │ │ │ └── TVCChannelSelectionViewController.m
│ │ │ ├── Channel View/
│ │ │ │ ├── Extras/
│ │ │ │ │ ├── TVCLogControllerHistoricLogFile.m
│ │ │ │ │ ├── TVCLogControllerInlineMediaService.m
│ │ │ │ │ └── TVCLogControllerOperationQueue.m
│ │ │ │ ├── TVCLogController.m
│ │ │ │ ├── TVCLogLine.m
│ │ │ │ ├── TVCLogPolicy.m
│ │ │ │ ├── TVCLogRenderer.m
│ │ │ │ ├── TVCLogScriptEventSink.m
│ │ │ │ ├── TVCLogView.m
│ │ │ │ ├── TVCLogViewInternalWK1.m
│ │ │ │ ├── TVCLogViewInternalWK2.m
│ │ │ │ └── TVCWK1AutoScroller.m
│ │ │ ├── Errors/
│ │ │ │ ├── TVCAlert.m
│ │ │ │ ├── TVCErrorMessagePopover.m
│ │ │ │ └── TVCErrorMessagePopoverController.m
│ │ │ ├── Input Text Field/
│ │ │ │ ├── TVCAutoExpandingTextField.m
│ │ │ │ ├── TVCAutoExpandingTokenField.m
│ │ │ │ ├── TVCTextFormatterMenu.m
│ │ │ │ ├── TVCTextViewWithIRCFormatter.m
│ │ │ │ ├── TVCValidatedComboBox.m
│ │ │ │ └── TVCValidatedTextField.m
│ │ │ ├── Main Window/
│ │ │ │ ├── TVCMainWindow.m
│ │ │ │ ├── TVCMainWindowAppearance.m
│ │ │ │ ├── TVCMainWindowChannelView.m
│ │ │ │ ├── TVCMainWindowLoadingScreen.m
│ │ │ │ ├── TVCMainWindowSegmentedControl.m
│ │ │ │ ├── TVCMainWindowSplitView.m
│ │ │ │ ├── TVCMainWindowTextView.m
│ │ │ │ ├── TVCMainWindowTextViewAppearance.m
│ │ │ │ └── TVCMainWindowTitlebarAccessoryView.m
│ │ │ ├── Preferences/
│ │ │ │ └── TVCNotificationConfigurationViewController.m
│ │ │ ├── Server List/
│ │ │ │ ├── TVCServerList.m
│ │ │ │ ├── TVCServerListAppearance.m
│ │ │ │ └── TVCServerListCell.m
│ │ │ ├── TVCAppearance.m
│ │ │ ├── TVCBasicTableView.m
│ │ │ ├── TVCContentNavigationOutlineView.m
│ │ │ ├── TVCDockIcon.m
│ │ │ └── User List/
│ │ │ ├── TVCMemberList.m
│ │ │ ├── TVCMemberListAppearance.m
│ │ │ ├── TVCMemberListCell.m
│ │ │ └── TVCMemberListUserInfoPopover.m
│ │ ├── Configurations/
│ │ │ └── Sandbox/
│ │ │ ├── Debug.entitlements
│ │ │ ├── Sandbox Disabled.entitlements
│ │ │ └── Standard Release.entitlements
│ │ ├── Resources/
│ │ │ ├── Images/
│ │ │ │ ├── Application/
│ │ │ │ │ ├── applicationIcon.icns
│ │ │ │ │ ├── applicationIcon.psd
│ │ │ │ │ └── applicationIconBirthday.icns
│ │ │ │ ├── Copyright Information for Images.txt
│ │ │ │ ├── Dock Icon Badges/
│ │ │ │ │ └── Photoshop/
│ │ │ │ │ ├── Mavericks/
│ │ │ │ │ │ ├── blueDockBadge.psd
│ │ │ │ │ │ ├── blueDockBadgeWithShadow.psd
│ │ │ │ │ │ ├── redDockBadge.psd
│ │ │ │ │ │ └── redDockBadgeWithShadow.psd
│ │ │ │ │ └── Yosemite/
│ │ │ │ │ └── redDockBadge.psd
│ │ │ │ ├── Encryption Badges/
│ │ │ │ │ ├── encryptionLockIconDark.tif
│ │ │ │ │ ├── encryptionLockIconDark@2x.tif
│ │ │ │ │ ├── encryptionLockIconLight.tif
│ │ │ │ │ └── encryptionLockIconLight@2x.tif
│ │ │ │ ├── IRC Formatting Colors/
│ │ │ │ │ ├── FormattingColor_Rainbow.tif
│ │ │ │ │ └── FormattingColor_Rainbow@2x.tif
│ │ │ │ ├── Status Badges/
│ │ │ │ │ ├── channelRoomStatusIconDarkActive.tif
│ │ │ │ │ ├── channelRoomStatusIconDarkActive@2x.tif
│ │ │ │ │ ├── channelRoomStatusIconDarkInactive.tif
│ │ │ │ │ ├── channelRoomStatusIconDarkInactive@2x.tif
│ │ │ │ │ ├── channelRoomStatusIconLightActive.tif
│ │ │ │ │ ├── channelRoomStatusIconLightActive@2x.tif
│ │ │ │ │ ├── channelRoomStatusIconLightInactive.tif
│ │ │ │ │ ├── channelRoomStatusIconLightInactive@2x.tif
│ │ │ │ │ ├── channelRoomStatusIconMavericksDark.psd
│ │ │ │ │ └── channelRoomStatusIconMavericksLight.psd
│ │ │ │ └── User Interface/
│ │ │ │ ├── Miscellaneous/
│ │ │ │ │ └── ErroneousTextFieldValueIndicator.tif
│ │ │ │ └── Server List/
│ │ │ │ └── Glass/
│ │ │ │ ├── VibrantDarkServerListViewPrivateMessageUserIconActive.tif
│ │ │ │ ├── VibrantDarkServerListViewPrivateMessageUserIconActive@2x.tif
│ │ │ │ ├── VibrantDarkServerListViewPrivateMessageUserIconInactive.tif
│ │ │ │ ├── VibrantDarkServerListViewPrivateMessageUserIconInactive@2x.tif
│ │ │ │ ├── VibrantLightServerListViewPrivateMessageUserIconActive.tif
│ │ │ │ ├── VibrantLightServerListViewPrivateMessageUserIconActive@2x.tif
│ │ │ │ ├── VibrantLightServerListViewPrivateMessageUserIconInactive.tif
│ │ │ │ └── VibrantLightServerListViewPrivateMessageUserIconInactive@2x.tif
│ │ │ ├── Language Files/
│ │ │ │ ├── _randomToken
│ │ │ │ └── en.lproj/
│ │ │ │ ├── Accessibility.strings
│ │ │ │ ├── BasicLanguage.strings
│ │ │ │ ├── CommonErrors.strings
│ │ │ │ ├── IRC.strings
│ │ │ │ ├── Notifications.strings
│ │ │ │ ├── OffTheRecord.strings
│ │ │ │ ├── Prompts.strings
│ │ │ │ ├── TDCAboutDialog.strings
│ │ │ │ ├── TDCAddressBookSheet.strings
│ │ │ │ ├── TDCChannelBanListSheet.strings
│ │ │ │ ├── TDCChannelInviteSheet.strings
│ │ │ │ ├── TDCChannelModifyModesSheet.strings
│ │ │ │ ├── TDCChannelModifyTopicSheet.strings
│ │ │ │ ├── TDCChannelPropertiesSheet.strings
│ │ │ │ ├── TDCChannelSpotlightController.strings
│ │ │ │ ├── TDCFileTransferDialog.strings
│ │ │ │ ├── TDCLicenseUpgradeEligibilitySheet.strings
│ │ │ │ ├── TDCPreferencesController.strings
│ │ │ │ ├── TDCPreferencesUserStyleSheet.strings
│ │ │ │ ├── TDCServerChannelListDialog.strings
│ │ │ │ ├── TDCServerEndpointListSheet.strings
│ │ │ │ ├── TDCServerPropertiesSheet.strings
│ │ │ │ ├── TLOLicenseManager.strings
│ │ │ │ ├── TVCMainWindow.strings
│ │ │ │ └── TVCNotificationConfigurationView.strings
│ │ │ ├── License Manager/
│ │ │ │ └── RemoteLicenseSystemPublicKey.pub
│ │ │ ├── Property Lists/
│ │ │ │ ├── Application Properties/
│ │ │ │ │ └── Info.plist
│ │ │ │ ├── IRCCommandIndexLocalData.plist
│ │ │ │ ├── IRCCommandIndexRemoteData.plist
│ │ │ │ ├── IRCNetworks.plist
│ │ │ │ ├── Preferences/
│ │ │ │ │ ├── KeysExcludedFromContainer.plist
│ │ │ │ │ ├── KeysExcludedFromExport.plist
│ │ │ │ │ ├── KeysExcludedFromMigrate.plist
│ │ │ │ │ ├── PreferenceKeyMasterList.plist
│ │ │ │ │ ├── RegisteredUserDefaults.plist
│ │ │ │ │ └── RegisteredUserDefaultsInContainer.plist
│ │ │ │ ├── StaticStore.plist
│ │ │ │ └── TemplateLineTypes.plist
│ │ │ ├── Scripting/
│ │ │ │ └── Script Files/
│ │ │ │ ├── Bundled Scripts/
│ │ │ │ │ ├── Installing Custom Scripts.txt
│ │ │ │ │ ├── date.scpt
│ │ │ │ │ └── moti.scpt
│ │ │ │ └── Textual Extras Installer/
│ │ │ │ ├── Create-Installers
│ │ │ │ ├── Installation Files/
│ │ │ │ │ └── Scripts/
│ │ │ │ │ ├── apps.scpt
│ │ │ │ │ ├── banhammer.scpt
│ │ │ │ │ ├── ffuu.scpt
│ │ │ │ │ ├── flip.scpt
│ │ │ │ │ ├── hermes.scpt
│ │ │ │ │ ├── music.scpt
│ │ │ │ │ ├── np.scpt
│ │ │ │ │ ├── o_o.scpt
│ │ │ │ │ ├── page.scpt
│ │ │ │ │ ├── qt.scpt
│ │ │ │ │ ├── radium.scpt
│ │ │ │ │ ├── reverse.scpt
│ │ │ │ │ ├── shell.scpt
│ │ │ │ │ ├── slap.scpt
│ │ │ │ │ ├── spotify.scpt
│ │ │ │ │ └── vlc.scpt
│ │ │ │ ├── Installer Helpers/
│ │ │ │ │ ├── Build-Extension-Package
│ │ │ │ │ ├── Build-Final-Package
│ │ │ │ │ └── Build-Scripts-Package
│ │ │ │ ├── Installer Resources/
│ │ │ │ │ └── en.lproj/
│ │ │ │ │ ├── Localizable.strings
│ │ │ │ │ └── Welcome.rtf
│ │ │ │ ├── Packages/
│ │ │ │ │ └── Textual-Extras.pkg
│ │ │ │ └── distribution.plist
│ │ │ ├── Styling/
│ │ │ │ ├── Bundled Styles/
│ │ │ │ │ ├── Astria/
│ │ │ │ │ │ ├── Templates/
│ │ │ │ │ │ │ └── encryptedMessageLock.mustache
│ │ │ │ │ │ ├── copyright.txt
│ │ │ │ │ │ ├── design.css
│ │ │ │ │ │ ├── inlineMedia.css
│ │ │ │ │ │ ├── scripts.js
│ │ │ │ │ │ └── settings.plist
│ │ │ │ │ ├── Equinox/
│ │ │ │ │ │ ├── LICENSE.txt
│ │ │ │ │ │ ├── Templates/
│ │ │ │ │ │ │ └── encryptedMessageLock.mustache
│ │ │ │ │ │ ├── design.css
│ │ │ │ │ │ ├── inlineMedia.css
│ │ │ │ │ │ ├── scripts.js
│ │ │ │ │ │ └── settings.plist
│ │ │ │ │ ├── Sapientia/
│ │ │ │ │ │ ├── Resources/
│ │ │ │ │ │ │ └── Documentation/
│ │ │ │ │ │ │ └── changelog.txt
│ │ │ │ │ │ ├── Templates/
│ │ │ │ │ │ │ └── encryptedMessageLock.mustache
│ │ │ │ │ │ ├── copyright.txt
│ │ │ │ │ │ ├── design.css
│ │ │ │ │ │ ├── inlineMedia.css
│ │ │ │ │ │ ├── scripts.js
│ │ │ │ │ │ └── settings.plist
│ │ │ │ │ ├── Simplified/
│ │ │ │ │ │ ├── Varieties/
│ │ │ │ │ │ │ ├── Dark/
│ │ │ │ │ │ │ │ ├── Templates/
│ │ │ │ │ │ │ │ │ └── encryptedMessageLock.mustache
│ │ │ │ │ │ │ │ ├── design.css
│ │ │ │ │ │ │ │ ├── inlineMedia.css
│ │ │ │ │ │ │ │ └── settings.plist
│ │ │ │ │ │ │ └── Light/
│ │ │ │ │ │ │ ├── Templates/
│ │ │ │ │ │ │ │ └── encryptedMessageLock.mustache
│ │ │ │ │ │ │ ├── design.css
│ │ │ │ │ │ │ ├── inlineMedia.css
│ │ │ │ │ │ │ └── settings.plist
│ │ │ │ │ │ ├── copyright.txt
│ │ │ │ │ │ ├── scripts.js
│ │ │ │ │ │ └── settings.plist
│ │ │ │ │ ├── Sulaco/
│ │ │ │ │ │ ├── LICENSE.txt
│ │ │ │ │ │ ├── Templates/
│ │ │ │ │ │ │ ├── newMessagePostedWithSender.mustache
│ │ │ │ │ │ │ └── newMessagePostedWithoutSender.mustache
│ │ │ │ │ │ ├── design.css
│ │ │ │ │ │ ├── inlineMedia.css
│ │ │ │ │ │ ├── scripts.js
│ │ │ │ │ │ └── settings.plist
│ │ │ │ │ ├── Tomorrow/
│ │ │ │ │ │ ├── Varieties/
│ │ │ │ │ │ │ ├── Dark/
│ │ │ │ │ │ │ │ ├── Templates/
│ │ │ │ │ │ │ │ │ └── encryptedMessageLock.mustache
│ │ │ │ │ │ │ │ ├── design.css
│ │ │ │ │ │ │ │ ├── inlineMedia.css
│ │ │ │ │ │ │ │ └── settings.plist
│ │ │ │ │ │ │ └── Light/
│ │ │ │ │ │ │ ├── Templates/
│ │ │ │ │ │ │ │ └── encryptedMessageLock.mustache
│ │ │ │ │ │ │ ├── design.css
│ │ │ │ │ │ │ ├── inlineMedia.css
│ │ │ │ │ │ │ └── settings.plist
│ │ │ │ │ │ ├── copyright.txt
│ │ │ │ │ │ ├── scripts.js
│ │ │ │ │ │ └── settings.plist
│ │ │ │ │ └── Total Sublime/
│ │ │ │ │ ├── Templates/
│ │ │ │ │ │ └── encryptedMessageLock.mustache
│ │ │ │ │ ├── copyright.txt
│ │ │ │ │ ├── design.css
│ │ │ │ │ ├── inlineMedia.css
│ │ │ │ │ ├── scripts.js
│ │ │ │ │ └── settings.plist
│ │ │ │ ├── JavaScript/
│ │ │ │ │ └── API/
│ │ │ │ │ ├── core.js
│ │ │ │ │ ├── corePrivate.js
│ │ │ │ │ └── private/
│ │ │ │ │ ├── conversationTracking.js
│ │ │ │ │ ├── core/
│ │ │ │ │ │ ├── clickMenuSelection.js
│ │ │ │ │ │ ├── documentBody.js
│ │ │ │ │ │ ├── events.js
│ │ │ │ │ │ ├── inlineMedia.js
│ │ │ │ │ │ ├── messageBuffer.js
│ │ │ │ │ │ └── scrollTo.js
│ │ │ │ │ ├── scriptSink.js
│ │ │ │ │ └── scroller/
│ │ │ │ │ ├── automatic.js
│ │ │ │ │ ├── automaticEmpty.js
│ │ │ │ │ └── state.js
│ │ │ │ └── Style Default Templates/
│ │ │ │ └── Version 4/
│ │ │ │ ├── baseLayout.css
│ │ │ │ ├── baseLayout.mustache
│ │ │ │ ├── dateIndicator.mustache
│ │ │ │ ├── encryptedMessageLock.mustache
│ │ │ │ ├── formattedMessageFragment.mustache
│ │ │ │ ├── historyIndicator.mustache
│ │ │ │ ├── messageBufferLoadingIndicator.mustache
│ │ │ │ ├── messageBufferSessionIndicator.mustache
│ │ │ │ ├── newMessagePostedWithSender.mustache
│ │ │ │ ├── newMessagePostedWithoutSender.mustache
│ │ │ │ ├── renderedChannelNameLinkResource.mustache
│ │ │ │ ├── renderedStandardAnchorLinkResource.mustache
│ │ │ │ └── sessionIndicator.mustache
│ │ │ └── User Interface/
│ │ │ ├── Appearance/
│ │ │ │ ├── TDCChannelSpotlightAppearance.plist
│ │ │ │ ├── TDCChannelSpotlightAppearanceTemplate.plist
│ │ │ │ ├── TVCMainWindowAppearance.plist
│ │ │ │ ├── TVCMainWindowAppearanceTemplate.plist
│ │ │ │ ├── TVCMainWindowTextViewAppearance.plist
│ │ │ │ ├── TVCMainWindowTextViewAppearanceTemplate.plist
│ │ │ │ ├── TVCMemberListAppearance.plist
│ │ │ │ ├── TVCMemberListAppearanceTemplate.plist
│ │ │ │ ├── TVCServerListAppearance.plist
│ │ │ │ └── TVCServerListAppearanceTemplate.plist
│ │ │ └── en.lproj/
│ │ │ ├── TDCAboutDialog.xib
│ │ │ ├── TDCAddressBookSheet.xib
│ │ │ ├── TDCChannelBanListSheet.xib
│ │ │ ├── TDCChannelInviteSheet.xib
│ │ │ ├── TDCChannelModifyModesSheet.xib
│ │ │ ├── TDCChannelModifyTopicSheet.xib
│ │ │ ├── TDCChannelPropertiesSheet.xib
│ │ │ ├── TDCChannelSpotlightController.xib
│ │ │ ├── TDCFileTransferDialog.xib
│ │ │ ├── TDCHighlightEntrySheet.xib
│ │ │ ├── TDCLicenseManagerDialog.xib
│ │ │ ├── TDCLicenseManagerMigrateAppStoreSheet.xib
│ │ │ ├── TDCLicenseManagerRecoverLostLicenseSheet.xib
│ │ │ ├── TDCLicenseUpgradeActivateSheet.xib
│ │ │ ├── TDCLicenseUpgradeDialog.xib
│ │ │ ├── TDCLicenseUpgradeEligibilitySheet.xib
│ │ │ ├── TDCNicknameColorSheet.xib
│ │ │ ├── TDCPreferences.xib
│ │ │ ├── TDCPreferencesUserStyleSheet.xib
│ │ │ ├── TDCProgressIndicatorSheet.xib
│ │ │ ├── TDCServerChangeNicknameSheet.xib
│ │ │ ├── TDCServerChannelListDialog.xib
│ │ │ ├── TDCServerEndpointListSheet.xib
│ │ │ ├── TDCServerHighlightListSheet.xib
│ │ │ ├── TDCServerPropertiesSheet.xib
│ │ │ ├── TDCWelcomeSheet.xib
│ │ │ ├── TVCAlert.xib
│ │ │ ├── TVCChannelSelectionView.xib
│ │ │ ├── TVCMainWindow.xib
│ │ │ ├── TVCNotificationConfigurationView.xib
│ │ │ └── TXCMainMenu.xib
│ │ └── Textual App.xcodeproj/
│ │ ├── project.pbxproj
│ │ └── xcshareddata/
│ │ └── xcschemes/
│ │ ├── Textual (App Store).xcscheme
│ │ ├── Textual (Debug).xcscheme
│ │ ├── Textual (Standard Release Sandboxed).xcscheme
│ │ └── Textual (Standard Release).xcscheme
│ ├── Plugins/
│ │ ├── Blowfish Encryption/
│ │ │ ├── ACKNOWLEDGEMENT.txt
│ │ │ ├── Blowfish Encryption Extension.xcodeproj/
│ │ │ │ ├── project.pbxproj
│ │ │ │ └── xcshareddata/
│ │ │ │ └── xcschemes/
│ │ │ │ └── Blowfish Encryption Extension.xcscheme
│ │ │ ├── Classes/
│ │ │ │ ├── BlowfishEncryption.h
│ │ │ │ ├── BlowfishEncryption.m
│ │ │ │ ├── BlowfishEncryptionBase.h
│ │ │ │ ├── BlowfishEncryptionBase.m
│ │ │ │ ├── BlowfishEncryptionKeyExchange.h
│ │ │ │ ├── BlowfishEncryptionKeyExchange.mm
│ │ │ │ ├── BlowfishEncryptionKeyExchangeBase.h
│ │ │ │ ├── BlowfishEncryptionKeyExchangeBase.mm
│ │ │ │ ├── NSDataHelper.h
│ │ │ │ ├── NSDataHelper.m
│ │ │ │ ├── TPIBlowfishEncryption.h
│ │ │ │ ├── TPIBlowfishEncryption.m
│ │ │ │ ├── TPIBlowfishEncryptionSwizzledClasses.h
│ │ │ │ └── TPIBlowfishEncryptionSwizzledClasses.m
│ │ │ ├── LICENSE-GPLv2.txt
│ │ │ ├── LICENSE.txt
│ │ │ └── Resources/
│ │ │ ├── Language Files/
│ │ │ │ └── en.lproj/
│ │ │ │ └── BasicLanguage.strings
│ │ │ ├── Property Lists/
│ │ │ │ └── Info.plist
│ │ │ └── User Interface/
│ │ │ └── en.lproj/
│ │ │ └── TPIBlowfishEncryption.xib
│ │ ├── Caffeine/
│ │ │ ├── Caffeine Extension.xcodeproj/
│ │ │ │ ├── project.pbxproj
│ │ │ │ └── xcshareddata/
│ │ │ │ └── xcschemes/
│ │ │ │ └── Caffeine Extension.xcscheme
│ │ │ ├── Classes/
│ │ │ │ ├── TPI_Caffeine.h
│ │ │ │ └── TPI_Caffeine.m
│ │ │ └── Resources/
│ │ │ ├── Language Files/
│ │ │ │ └── en.lproj/
│ │ │ │ └── BasicLanguage.strings
│ │ │ ├── Property Lists/
│ │ │ │ └── Info.plist
│ │ │ └── User Interface/
│ │ │ └── en.lproj/
│ │ │ └── TPI_Caffeine.xib
│ │ ├── Chat Filter/
│ │ │ ├── Chat Filter Extension.xcodeproj/
│ │ │ │ └── project.pbxproj
│ │ │ ├── Classes/
│ │ │ │ ├── TPI_ChatFilter.h
│ │ │ │ ├── TPI_ChatFilter.m
│ │ │ │ ├── TPI_ChatFilterEditFilterSheet.h
│ │ │ │ ├── TPI_ChatFilterEditFilterSheet.m
│ │ │ │ ├── TPI_ChatFilterExtension.h
│ │ │ │ ├── TPI_ChatFilterExtension.m
│ │ │ │ ├── TPI_ChatFilterInternal.h
│ │ │ │ ├── TPI_ChatFilterLogic.h
│ │ │ │ ├── TPI_ChatFilterLogic.m
│ │ │ │ ├── TPI_NumberOnlyTextFieldFormatter.h
│ │ │ │ └── TPI_NumberOnlyTextFieldFormatter.m
│ │ │ └── Resources/
│ │ │ ├── Language Files/
│ │ │ │ └── en.lproj/
│ │ │ │ ├── TPI_ChatFilterEditFilterSheet.strings
│ │ │ │ ├── TPI_ChatFilterExtension.strings
│ │ │ │ └── TPI_ChatFilterLogic.strings
│ │ │ ├── Property Lists/
│ │ │ │ └── Info.plist
│ │ │ └── User Interface/
│ │ │ └── en.lproj/
│ │ │ ├── TPI_ChatFilterEditFilterSheet.xib
│ │ │ └── TPI_ChatFilterExtension.xib
│ │ ├── Sample Code/
│ │ │ └── Preference Pane/
│ │ │ ├── Classes/
│ │ │ │ ├── TPI_PreferencePaneExample.h
│ │ │ │ └── TPI_PreferencePaneExample.m
│ │ │ ├── PreferencePaneExample.xcodeproj/
│ │ │ │ └── project.pbxproj
│ │ │ └── Resources/
│ │ │ ├── Property Lists/
│ │ │ │ └── Info.plist
│ │ │ └── User Interface/
│ │ │ └── PreferencePane.xib
│ │ ├── Smiley Converter/
│ │ │ ├── Classes/
│ │ │ │ ├── TPISmileyConverter.h
│ │ │ │ └── TPISmileyConverter.m
│ │ │ ├── Resources/
│ │ │ │ ├── Language Files/
│ │ │ │ │ └── en.lproj/
│ │ │ │ │ └── BasicLanguage.strings
│ │ │ │ ├── Property Lists/
│ │ │ │ │ ├── Info.plist
│ │ │ │ │ ├── conversionTable.plist
│ │ │ │ │ └── conversionTable2.plist
│ │ │ │ └── User Interface/
│ │ │ │ └── en.lproj/
│ │ │ │ └── TPISmileyConverter.xib
│ │ │ └── Smiley Converter Extension.xcodeproj/
│ │ │ └── project.pbxproj
│ │ ├── System Profiler/
│ │ │ ├── Classes/
│ │ │ │ ├── SystemProfiler.h
│ │ │ │ ├── TPISystemProfiler.h
│ │ │ │ ├── TPISystemProfiler.m
│ │ │ │ ├── TPI_SP_SysInfo.h
│ │ │ │ └── TPI_SP_SysInfo.m
│ │ │ ├── Resources/
│ │ │ │ ├── Language Files/
│ │ │ │ │ └── en.lproj/
│ │ │ │ │ └── BasicLanguage.strings
│ │ │ │ ├── Property Lists/
│ │ │ │ │ ├── Info.plist
│ │ │ │ │ └── MacintoshModels.plist
│ │ │ │ └── User Interface/
│ │ │ │ └── en.lproj/
│ │ │ │ └── TPISystemProfiler.xib
│ │ │ └── System Profiler Extension.xcodeproj/
│ │ │ └── project.pbxproj
│ │ ├── User Insights/
│ │ │ ├── Classes/
│ │ │ │ ├── TPIUserInsights.h
│ │ │ │ └── TPIUserInsights.m
│ │ │ ├── Resources/
│ │ │ │ ├── Language Files/
│ │ │ │ │ └── en.lproj/
│ │ │ │ │ └── BasicLanguage.strings
│ │ │ │ └── Property Lists/
│ │ │ │ └── Info.plist
│ │ │ └── User Insights Extension.xcodeproj/
│ │ │ └── project.pbxproj
│ │ ├── Wiki Link Parser/
│ │ │ ├── Classes/
│ │ │ │ ├── TPIWikiStyleLinkParser.h
│ │ │ │ └── TPIWikiStyleLinkParser.m
│ │ │ ├── Resources/
│ │ │ │ ├── Language Files/
│ │ │ │ │ └── en.lproj/
│ │ │ │ │ └── BasicLanguage.strings
│ │ │ │ ├── Property Lists/
│ │ │ │ │ └── Info.plist
│ │ │ │ └── User Interface/
│ │ │ │ └── en.lproj/
│ │ │ │ └── TPIWikiStyleLinkParser.xib
│ │ │ └── Wiki-style Link Parser Extension.xcodeproj/
│ │ │ ├── project.pbxproj
│ │ │ └── xcshareddata/
│ │ │ └── xcschemes/
│ │ │ └── Wiki-style Link Parser Extension.xcscheme
│ │ └── ZNC Additions/
│ │ ├── Classes/
│ │ │ ├── TPI_ZNCAdditions.h
│ │ │ └── TPI_ZNCAdditions.m
│ │ ├── Resources/
│ │ │ ├── Language Files/
│ │ │ │ └── en.lproj/
│ │ │ │ └── BasicLanguage.strings
│ │ │ └── Property Lists/
│ │ │ └── Info.plist
│ │ └── ZNC Additions Extension.xcodeproj/
│ │ └── project.pbxproj
│ └── Shared/
│ ├── Headers/
│ │ ├── External Libraries/
│ │ │ ├── GCDAsyncSocket.h
│ │ │ └── GCDAsyncSocketExtensions.h
│ │ ├── IRCConnectionConfig.h
│ │ ├── IRCConnectionErrors.h
│ │ ├── Internal/
│ │ │ └── IRCConnectionConfigInternal.h
│ │ ├── Private/
│ │ │ ├── NSObjectHelperPrivate.h
│ │ │ ├── TPCPreferencesPrivate.h
│ │ │ ├── TPCPreferencesUserDefaultsPrivate.h
│ │ │ └── TVCLogLineXPCPrivate.h
│ │ ├── StaticDefinitions.h
│ │ ├── TLOLocalization.h
│ │ ├── TLOTimer.h
│ │ ├── TPCPreferences.h
│ │ └── TPCPreferencesUserDefaults.h
│ ├── Helpers/
│ │ └── Cocoa (Objective-C)/
│ │ └── NSObjectHelper.m
│ ├── IRC/
│ │ ├── IRCConnectionConfig.m
│ │ └── IRCConnectionErrors.m
│ ├── Library/
│ │ ├── External Libraries/
│ │ │ └── Sockets/
│ │ │ ├── GCDAsyncSocket-patch.txt
│ │ │ ├── GCDAsyncSocket.m
│ │ │ └── GCDAsyncSocketExtensions.m
│ │ ├── TLOLocalization.m
│ │ ├── TLOLocalization.swift
│ │ └── TLOTimer.m
│ ├── Preferences/
│ │ ├── TPCPreferences.m
│ │ └── TPCPreferencesUserDefaults.m
│ └── Views/
│ └── Channel View/
│ └── TVCLogLineXPC.m
└── XPC Services/
├── Historic Log File Manager/
│ ├── Classes/
│ │ ├── HLSHistoricLogLineEntityMigration.m
│ │ ├── HLSHistoricLogProcessMain.m
│ │ ├── HLSHistoricLogViewContext.m
│ │ ├── HSLHistoricLogProcessDelegate.m
│ │ ├── Headers/
│ │ │ └── Private/
│ │ │ ├── HLSHistoricLogLineEntityMigrationPrivate.h
│ │ │ ├── HLSHistoricLogProcessMainPrivate.h
│ │ │ ├── HLSHistoricLogProtocol.h
│ │ │ ├── HLSHistoricLogViewContextPrivate.h
│ │ │ ├── HSLHistoricLogPCHPrivate.h
│ │ │ └── HSLHistoricLogProcessDelegatePrivate.h
│ │ └── main.m
│ ├── Configurations/
│ │ └── Sandbox/
│ │ └── Release.entitlements
│ ├── Historic Log File Manager.xcodeproj/
│ │ └── project.pbxproj
│ └── Resources/
│ ├── Data Models/
│ │ ├── HistoricLogFileStorageModel.xcdatamodeld/
│ │ │ ├── .xccurrentversion
│ │ │ ├── LogControllerStorageModel (model 2).xcdatamodel/
│ │ │ │ └── contents
│ │ │ └── LogControllerStorageModel (model 3).xcdatamodel/
│ │ │ └── contents
│ │ └── HistoricLogFileStorageModel.xcmappingmodel/
│ │ └── xcmapping.xml
│ └── Property Lists/
│ └── Info.plist
├── IRC Remote Connection Manager/
│ ├── Classes/
│ │ ├── Headers/
│ │ │ └── Private/
│ │ │ ├── IRCConnectionPrivate.h
│ │ │ ├── RCMConnectionManagerProtocol.h
│ │ │ ├── RCMProcessDelegatePrivate.h
│ │ │ ├── RCMProcessMainPrivate.h
│ │ │ ├── RCMProcessPCHPrivate.h
│ │ │ └── SwiftBridgingHeaderPrivate.h
│ │ ├── IRC/
│ │ │ ├── IRCConnection.swift
│ │ │ ├── IRCConnectionSocket.swift
│ │ │ ├── IRCConnectionSocketClassic.swift
│ │ │ └── IRCConnectionSocketNWF.swift
│ │ └── Service/
│ │ ├── RCMProcessDelegate.m
│ │ ├── RCMProcessMain.m
│ │ └── main.m
│ ├── Configurations/
│ │ └── Sandbox/
│ │ └── Release.entitlements
│ ├── IRC Remote Connection Manager.xcodeproj/
│ │ └── project.pbxproj
│ └── Resources/
│ ├── Language Files/
│ │ └── en.lproj/
│ │ └── ConnectionErrors.strings
│ └── Property Lists/
│ └── Info.plist
└── Inline Content Loader/
├── Build Scripts/
│ └── BuildExtensions.sh
├── Classes/
│ ├── Headers/
│ │ ├── ICLHelpers.h
│ │ ├── ICLInlineContentModule.h
│ │ ├── ICLMediaAssessment.h
│ │ ├── ICLMediaAssessor.h
│ │ ├── ICLMediaType.h
│ │ ├── ICLPayload.h
│ │ ├── ICLPluginProtocol.h
│ │ ├── Internal/
│ │ │ ├── ICLInlineContentModuleInternal.h
│ │ │ ├── ICLMediaAssessmentInternal.h
│ │ │ └── ICLPayloadInternal.h
│ │ └── Private/
│ │ ├── CoreModulesImportsPrivate.h
│ │ ├── ICLInlineContentModulePrivate.h
│ │ ├── ICLInlineContentProtocol.h
│ │ ├── ICLPayloadPrivate.h
│ │ ├── ICLPluginManagerPrivate.h
│ │ ├── ICLProcessDelegatePrivate.h
│ │ ├── ICLProcessMainPrivate.h
│ │ └── ICLProcessPCHPrivate.h
│ ├── Modules/
│ │ ├── Assessed Media/
│ │ │ ├── ICMAssessedMedia.h
│ │ │ └── ICMAssessedMedia.m
│ │ └── Root Classes/
│ │ ├── ICMInlineHTML.h
│ │ ├── ICMInlineHTML.m
│ │ ├── ICMInlineImage.h
│ │ ├── ICMInlineImage.m
│ │ ├── ICMInlineVideo.h
│ │ └── ICMInlineVideo.m
│ └── Service/
│ ├── ICLHelpers.m
│ ├── ICLInlineContentModule.m
│ ├── ICLMediaAssessment.m
│ ├── ICLMediaAssessor.m
│ ├── ICLPayloadLocal.m
│ ├── ICLPayloadShared.m
│ ├── ICLPluginManager.m
│ ├── ICLProcessDelegate.m
│ ├── ICLProcessMain.m
│ └── main.m
├── Configurations/
│ └── Sandbox/
│ └── Release.entitlements
├── Extensions/
│ └── Core Media/
│ ├── Classes/
│ │ ├── Headers/
│ │ │ └── Private/
│ │ │ ├── ICPCoreMediaPCHPrivate.h
│ │ │ └── ICPCoreMediaPrivate.h
│ │ ├── ICPCoreMedia.m
│ │ └── Modules/
│ │ ├── Common Images/
│ │ │ ├── ICMCommonInlineImages.h
│ │ │ └── ICMCommonInlineImages.m
│ │ ├── Common Videos/
│ │ │ ├── ICMCommonInlineVideos.h
│ │ │ └── ICMCommonInlineVideos.m
│ │ ├── Dailymotion/
│ │ │ ├── ICMDailymotion.h
│ │ │ └── ICMDailymotion.m
│ │ ├── Gyazo/
│ │ │ ├── ICMGyazo.h
│ │ │ └── ICMGyazo.m
│ │ ├── Imgur .gifv/
│ │ │ ├── ICMImgurGifv.h
│ │ │ └── ICMImgurGifv.m
│ │ ├── Pornhub/
│ │ │ ├── ICMPornhub.h
│ │ │ └── ICMPornhub.m
│ │ ├── Streamable/
│ │ │ ├── ICMStreamable.h
│ │ │ └── ICMStreamable.m
│ │ ├── Twitch Clips/
│ │ │ ├── ICMTwitchClips.h
│ │ │ └── ICMTwitchClips.m
│ │ ├── Twitch Live/
│ │ │ ├── ICMTwitchLive.h
│ │ │ └── ICMTwitchLive.m
│ │ ├── Twitter/
│ │ │ ├── ICMTweet.h
│ │ │ └── ICMTweet.m
│ │ ├── Vimeo/
│ │ │ ├── ICMVimeo.h
│ │ │ └── ICMVimeo.m
│ │ ├── YouTube/
│ │ │ ├── ICMYouTube.h
│ │ │ └── ICMYouTube.m
│ │ └── xkcd/
│ │ ├── ICMXkcd.h
│ │ └── ICMXkcd.m
│ ├── Inline Content Loader Core Media.xcodeproj/
│ │ └── project.pbxproj
│ └── Resources/
│ ├── Modules/
│ │ ├── Dailymotion/
│ │ │ └── ICMDailymotion.mustache
│ │ ├── Pornhub/
│ │ │ └── ICMPornhub.mustache
│ │ ├── Twitch Clips/
│ │ │ └── ICMTwitchClips.mustache
│ │ ├── Twitch Live/
│ │ │ └── ICMTwitchLive.mustache
│ │ ├── Twitter/
│ │ │ └── ICMTweet.js
│ │ ├── Vimeo/
│ │ │ └── ICMVimeo.mustache
│ │ └── YouTube/
│ │ └── ICMYouTube.mustache
│ └── Property Lists/
│ └── Info.plist
├── Inline Content Loader.xcodeproj/
│ └── project.pbxproj
└── Resources/
├── Modules/
│ ├── ICMInlineHTML.css
│ ├── ICMInlineHTML.js
│ ├── ICMInlineHTML.mustache
│ ├── ICMInlineImage.css
│ ├── ICMInlineImage.js
│ ├── ICMInlineImage.mustache
│ ├── ICMInlineVideo.css
│ ├── ICMInlineVideo.js
│ ├── ICMInlineVideo.mustache
│ └── InlineImageLiveResize.js
└── Property Lists/
└── Info.plist
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
*~
*~.*
.DS_Store
.LSOverride
*.mode1v3
*.mode2v3
*.pbxuser
*.perspectivev3
*.pyc
.tmp
build
Build Results
xcuserdata
*.xcworkspace
Sources/App/Resources/Scripting/Script Files/Textual Extras Installer/Installation Files/Extensions/*
Sources/App/Resources/Scripting/Script Files/Textual Extras Installer/Packages/MACAPPSTORE/*
Sources/App/Resources/Scripting/Script Files/Textual Extras Installer/Packages/STANDALONE/*
!/Configurations/Build
================================================
FILE: .gitmodules
================================================
[submodule "Frameworks/Auto Hyperlinks"]
path = Frameworks/Auto Hyperlinks
url = https://github.com/Codeux-Software/Auto-Hyperlinks.git
[submodule "Frameworks/Cocoa Extensions"]
path = Frameworks/Cocoa Extensions
url = https://github.com/Codeux-Software/Cocoa-Extensions.git
[submodule "Frameworks/Encryption Kit"]
path = Frameworks/Encryption Kit
url = https://github.com/Codeux-Software/Encryption-Kit.git
[submodule "Frameworks/Static Libraries"]
path = Frameworks/Static Libraries
url = https://github.com/Codeux-Software/Static-Libraries.git
[submodule "Sources/Plugins/Sample Code/Swift Bot"]
path = Sources/Plugins/Sample Code/Swift Bot
url = https://github.com/Codeux/Textual-Swift-Plugin.git
================================================
FILE: Configurations/Build/Code Signing Identity.xcconfig
================================================
// This is the code signing identity used by all projects.
CODE_SIGN_IDENTITY = Mac Developer
// Set these values to empty
DEVELOPMENT_TEAM = 8482Q6EPL6
PROVISIONING_PROFILE_SPECIFIER = 8482Q6EPL6/
================================================
FILE: Configurations/Build/Common/Foundation Debug.xcconfig
================================================
// Foundation Debug.xcconfig acts as a base for ALL projects.
// This configuration should NEVER contain any settings
// which may be unique to a specific project.
#include "Foundation.xcconfig"
DEPLOYMENT_POSTPROCESSING = NO
ENABLE_NS_ASSERTIONS = YES
ENABLE_TESTABILITY = YES
GCC_OPTIMIZATION_LEVEL = 0
GCC_PREPROCESSOR_DEFINITIONS = DEBUG
ONLY_ACTIVE_ARCH = YES
RUN_CLANG_STATIC_ANALYZER = NO
SWIFT_COMPILATION_MODE = singlefile
SWIFT_OPTIMIZATION_LEVEL = -Onone
VERSION_INFO_BUILDER = ${USER}
//
// On Xcode 16, Textual failed to run in debug mode because
// a "Textual.debug.dylib" file was missing in the @rpath
// of extensions and services. Going to disable this feature
// of Xcode until a later release of Xcode.
//
// From Xcode 16 beta 1 release notes:
//
// Some large or complex projects may fail to build and
// run if they are scanning for specific Mach-O sections
// in their binaries. (123416939)
//
// Workaround: Try setting the build setting ENABLE_DEBUG_DYLIB=NO.
// This will disable the debug dylib that enables the new preview
// execution mode. Setting this to NO will still allow you to
// preview in Xcode 16 Seed 1 using the legacy execution mode,
// but support for this mode will be removed in a future build.
//
ENABLE_DEBUG_DYLIB = NO
================================================
FILE: Configurations/Build/Common/Foundation.xcconfig
================================================
// Foundation.xcconfig acts as a base for ALL projects.
// This configuration should NEVER contain any settings
// which may be unique to a specific project.
ALWAYS_SEARCH_USER_PATHS = NO
APPLY_RULES_IN_COPY_FILES = YES
ARCHS = $(ARCHS_STANDARD)
CLANG_ANALYZER_GCD_PERFORMANCE = YES
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES
CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES
CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES
CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES
CLANG_CXX_LANGUAGE_STANDARD = gnu++0x
CLANG_ENABLE_MODULES = YES
CLANG_ENABLE_OBJC_ARC = YES
CLANG_USE_OPTIMIZATION_PROFILE = NO
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES
CLANG_WARN_BOOL_CONVERSION = YES
CLANG_WARN_COMMA = YES
CLANG_WARN_CONSTANT_CONVERSION = YES
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES
CLANG_WARN_EMPTY_BODY = YES
CLANG_WARN_ENUM_CONVERSION = YES
CLANG_WARN_INFINITE_RECURSION = YES
CLANG_WARN_INT_CONVERSION = YES
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES
CLANG_WARN_SEMICOLON_BEFORE_METHOD_BODY = YES
CLANG_WARN_STRICT_PROTOTYPES = YES
CLANG_WARN_SUSPICIOUS_MOVE = YES
CLANG_WARN_UNREACHABLE_CODE = YES
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES
CODE_SIGN_ENTITLEMENTS =
COMBINE_HIDPI_IMAGES = YES
CONFIGURATION_BUILD_DIR = $(PROJECT_DIR)/Build Results/$(CONFIGURATION)
COPY_PHASE_STRIP = NO
DEAD_CODE_STRIPPING = YES
DEBUG_INFORMATION_FORMAT = dwarf-with-dsym
DEFINES_MODULE = YES
DEPLOYMENT_POSTPROCESSING = YES
ENABLE_HARDENED_RUNTIME = YES
ENABLE_NS_ASSERTIONS = YES
ENABLE_STRICT_OBJC_MSGSEND = NO
FRAMEWORK_SEARCH_PATHS =
GCC_C_LANGUAGE_STANDARD = gnu99
GCC_DYNAMIC_NO_PIC = YES
GCC_ENABLE_OBJC_EXCEPTIONS = YES
GCC_GENERATE_DEBUGGING_SYMBOLS = YES
GCC_NO_COMMON_BLOCKS = YES
GCC_OPTIMIZATION_LEVEL = fast
GCC_PREFIX_HEADER =
GCC_UNROLL_LOOPS = YES
GCC_WARN_64_TO_32_BIT_CONVERSION = YES
GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = YES
GCC_WARN_ABOUT_MISSING_NEWLINE = YES
GCC_WARN_ABOUT_RETURN_TYPE = YES
GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = NO
GCC_WARN_UNDECLARED_SELECTOR = NO
GCC_WARN_UNINITIALIZED_AUTOS = YES
GCC_WARN_UNUSED_FUNCTION = YES
GCC_WARN_UNUSED_LABEL = YES
GCC_WARN_UNUSED_VARIABLE = YES
HEADER_SEARCH_PATHS =
INFOPLIST_OUTPUT_FORMAT = binary
LD_NO_PIE = YES
LD_NO_PIE[arch=arm64] = NO
LD_RUNPATH_SEARCH_PATHS = @loader_path/../Frameworks @executable_path/../Frameworks
LIBRARY_SEARCH_PATHS =
MACOSX_DEPLOYMENT_TARGET = 11.0
ONLY_ACTIVE_ARCH = NO
OTHER_CFLAGS = -Xclang -fobjc-runtime-has-weak
PLIST_FILE_OUTPUT_FORMAT = binary
PRODUCT_BUNDLE_IDENTIFIER =
REMOVE_HEADERS_FROM_EMBEDDED_BUNDLES = YES
RUN_CLANG_STATIC_ANALYZER = NO
STRINGS_FILE_OUTPUT_ENCODING = binary
SWIFT_COMPILATION_MODE = wholemodule
SWIFT_INSTALL_OBJC_HEADER = NO
SWIFT_OPTIMIZATION_LEVEL = -O
SWIFT_VERSION = 5.0
VERSION_INFO_BUILDER = Codeux Software, LLC
WARNING_CFLAGS = -Wobjc-circular-container -Winfinite-recursion
#include "../Code Signing Identity.xcconfig"
================================================
FILE: Configurations/Build/Common/Preserve Symbols.xcconfig
================================================
// It is important to preserve symbols and code that is
// not directly used so that extensions can use them.
DEAD_CODE_STRIPPING = NO
GCC_SYMBOLS_PRIVATE_EXTERN = NO
STRIP_STYLE = non-global
================================================
FILE: Configurations/Build/Common/Textual App.xcconfig
================================================
// Main application
TEXTUAL_WORKSPACE_DIR = ${PROJECT_DIR}/../..
HEADER_SEARCH_PATHS = "${TEXTUAL_WORKSPACE_TEMP_DIR}/Build Headers/" "${TEXTUAL_WORKSPACE_DIR}/Sources/Shared/Headers/**"
FRAMEWORK_SEARCH_PATHS = "${TEXTUAL_WORKSPACE_TEMP_DIR}/SharedBuildProducts-Frameworks/**" "${TEXTUAL_WORKSPACE_DIR}/Frameworks/**"
LIBRARY_SEARCH_PATHS = "${TEXTUAL_WORKSPACE_TEMP_DIR}/SharedBuildProducts-Frameworks/**" "${TEXTUAL_WORKSPACE_DIR}/Frameworks/**"
PRODUCT_BUNDLE_IDENTIFIER = ${TEXTUAL_BUNDLE_IDENTIFIER}
PRODUCT_NAME = ${TEXTUAL_PRODUCT_NAME}
WRAPPER_EXTENSION = app
PRODUCT_MODULE_NAME = Textual
CONFIGURATION_BUILD_DIR = $(TEXTUAL_WORKSPACE_DIR)/Build Results/$(CONFIGURATION)
GCC_PREFIX_HEADER = ${PROJECT_DIR}/Classes/Headers/Private/TextualPrivate.h
SWIFT_OBJC_BRIDGING_HEADER = ${PROJECT_DIR}/Classes/Headers/Private/SwiftBridgingHeaderPrivate.h
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
REMOVE_HEADERS_FROM_EMBEDDED_BUNDLES = NO
INFOPLIST_FILE = ${TEXTUAL_WORKSPACE_TEMP_DIR}/Info.plist
#include "Preserve Symbols.xcconfig"
================================================
FILE: Configurations/Build/Common/Textual Extensions.xcconfig
================================================
// Textual Extensions *.xcconfig file contains settings that
// are specific to extensions for Textual (main application).
// TEXTUAL_WORKSPACE_DIR is replaced by the build script
TEXTUAL_WORKSPACE_DIR = ${PROJECT_DIR}/../../..
CONFIGURATION_BUILD_DIR = ${TEXTUAL_WORKSPACE_TEMP_DIR}/SharedBuildProducts-Extensions
CODE_SIGN_ENTITLEMENTS = ${TEXTUAL_WORKSPACE_DIR}/Configurations/Sandbox/Inherited.entitlements
HEADER_SEARCH_PATHS = ${inherited} "${TEXTUAL_WORKSPACE_TEMP_DIR}/Build Headers/" "${TEXTUAL_WORKSPACE_DIR}/Sources/App/Classes/Headers/**" "${TEXTUAL_WORKSPACE_DIR}/Sources/Shared/Headers/**"
LIBRARY_SEARCH_PATHS = ${inherited} "${TEXTUAL_WORKSPACE_TEMP_DIR}/SharedBuildProducts-Frameworks/**" "${TEXTUAL_WORKSPACE_DIR}/Frameworks/**"
FRAMEWORK_SEARCH_PATHS = ${inherited} "${TEXTUAL_WORKSPACE_TEMP_DIR}/SharedBuildProducts-Frameworks/**" "${TEXTUAL_WORKSPACE_DIR}/Frameworks/**"
WRAPPER_EXTENSION = bundle
PROVISIONING_PROFILE =
PROVISIONING_PROFILE_SPECIFIER =
BUNDLE_LOADER = ${TEXTUAL_PRODUCT_BINARY}
================================================
FILE: Configurations/Build/Common/Textual.xcconfig
================================================
// Main application, extensions, and XPC services
TEXTUAL_PRODUCT_NAME = Textual
// TEXTUAL_PRODUCT_LOCATION is replaced by the build script
TEXTUAL_PRODUCT_LOCATION = /Applications/${TEXTUAL_PRODUCT_NAME}.app
// TEXTUAL_PRODUCT_BINARY is replaced by the build script
TEXTUAL_PRODUCT_BINARY = ${TEXTUAL_PRODUCT_LOCATION}/Contents/MacOS/${TEXTUAL_PRODUCT_NAME}
// TEXTUAL_WORKSPACE_TEMP_DIR should be same for every
// project so only override TEXTUAL_WORKSPACE_DIR, not this.
TEXTUAL_WORKSPACE_TEMP_DIR = ${TEXTUAL_WORKSPACE_DIR}/.tmp
SHARED_PRECOMPS_DIR = ${TEXTUAL_WORKSPACE_TEMP_DIR}/SharedPCH
DWARF_DSYM_FOLDER_PATH = ${TEXTUAL_WORKSPACE_TEMP_DIR}/SharedSymbols
// TEXTUAL_BUILT_AS_UNIVERSAL_BINARY acts an easy way to
// modify code based on the type of binary being built.
// As with other feature flags, changing this value only
// adds or excludes certain chunks of code. It doesn't
// change the underlying build process.
TEXTUAL_BUILT_AS_UNIVERSAL_BINARY = 1
================================================
FILE: Configurations/Build/Common/XPC Service - ICL Extensions.xcconfig
================================================
// Inline Content Loader XPC service extensions
// TEXTUAL_WORKSPACE_DIR is replaced by the build script
TEXTUAL_WORKSPACE_DIR = ${PROJECT_DIR}/../../../..
// ICL_WORKSPACE_DIR is NOT replaced by the build script
ICL_WORKSPACE_DIR = ${TEXTUAL_WORKSPACE_DIR}/XPC Services/Inline Content Loader
// ICL_PRODUCT_LOCATION is replaced by the build script
ICL_PRODUCT_LOCATION = ${TEXTUAL_PRODUCT_LOCATION}/Contents/XPCServices/InlineContentLoader.xpc
// ICL_PRODUCT_BINARY is replaced by the build script
ICL_PRODUCT_BINARY = ${ICL_PRODUCT_LOCATION}/Contents/MacOS/InlineContentLoader
CONFIGURATION_BUILD_DIR = ${TEXTUAL_WORKSPACE_TEMP_DIR}/SharedBuildProducts-ICLExtension
HEADER_SEARCH_PATHS = ${inherited} "${ICL_WORKSPACE_DIR}/Classes/Headers/**" "${ICL_WORKSPACE_DIR}/Classes/Modules/**" "${TEXTUAL_WORKSPACE_DIR}/Sources/Shared/Headers/**"
LIBRARY_SEARCH_PATHS = ${inherited} "${TEXTUAL_WORKSPACE_TEMP_DIR}/SharedBuildProducts-Frameworks/**" "${TEXTUAL_WORKSPACE_DIR}/Frameworks/**"
FRAMEWORK_SEARCH_PATHS = ${inherited} "${TEXTUAL_WORKSPACE_TEMP_DIR}/SharedBuildProducts-Frameworks/**" "${TEXTUAL_WORKSPACE_DIR}/Frameworks/**"
WRAPPER_EXTENSION = bundle
PROVISIONING_PROFILE =
PROVISIONING_PROFILE_SPECIFIER =
BUNDLE_LOADER = ${ICL_PRODUCT_BINARY}
================================================
FILE: Configurations/Build/Common/XPC Service - ICL.xcconfig
================================================
// Inline content loader XPC service
#include "Preserve Symbols.xcconfig"
================================================
FILE: Configurations/Build/Common/XPC Services.xcconfig
================================================
// XPC services
// TEXTUAL_WORKSPACE_DIR is replaced by the build script
TEXTUAL_WORKSPACE_DIR = ${PROJECT_DIR}/../..
CONFIGURATION_BUILD_DIR = ${TEXTUAL_WORKSPACE_TEMP_DIR}/SharedBuildProducts-XPCServices
CODE_SIGN_ENTITLEMENTS = ${TEXTUAL_WORKSPACE_DIR}/Configurations/Sandbox/Inherited.entitlements
HEADER_SEARCH_PATHS = $(inherited) "${TEXTUAL_WORKSPACE_TEMP_DIR}/Build Headers/" "${TEXTUAL_WORKSPACE_DIR}/Sources/Shared/Headers/**"
LIBRARY_SEARCH_PATHS = $(inherited) "${TEXTUAL_WORKSPACE_TEMP_DIR}/SharedBuildProducts-Frameworks/**" "${TEXTUAL_WORKSPACE_DIR}/Frameworks/**"
FRAMEWORK_SEARCH_PATHS = $(inherited) "${TEXTUAL_WORKSPACE_TEMP_DIR}/SharedBuildProducts-Frameworks/**" "${TEXTUAL_WORKSPACE_DIR}/Frameworks/**"
WRAPPER_EXTENSION = xpc
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) TEXTUAL_BUILDING_XPC_SERVICE=1
// Link against frameworks in app itself rather than creating copies
// ./(self) ../(Contents) ../(.xpc bundle) ../(XPCServices) ../(Contents)
LD_RUNPATH_SEARCH_PATHS = $(inherited) @loader_path/../../../../Frameworks
================================================
FILE: Configurations/Build/Debug/Enabled Features.xcconfig
================================================
// The main project of Textual, its extensions, and its XPC services
// all inherit one of these configuration files to allow them to
// selectively disable code based on which features are enabled.
// These macros that are used to disable and enable the inclusion
// of certain segments of code. Toggling one of these flags does not
// guarantee that the toggled feature will work. These only toggle the code.
// Not add additional resource files that the code may be dependent on.
// To add new feature flags, modify UpdateFeatureFlags.sh
TEXTUAL_BUILT_INSIDE_SANDBOX=1
TEXTUAL_BUILT_WITH_ADVANCED_ENCRYPTION=1
TEXTUAL_BUILT_WITH_LICENSE_MANAGER=1
================================================
FILE: Configurations/Build/Debug/Textual App.xcconfig
================================================
#include "../Common/Foundation Debug.xcconfig"
#include "Textual.xcconfig"
#include "../Common/Textual App.xcconfig"
CODE_SIGN_ENTITLEMENTS = ${PROJECT_DIR}/Configurations/Sandbox/Debug.entitlements
================================================
FILE: Configurations/Build/Debug/Textual Extensions.xcconfig
================================================
#include "../Common/Foundation Debug.xcconfig"
#include "Textual.xcconfig"
#include "../Common/Textual Extensions.xcconfig"
================================================
FILE: Configurations/Build/Debug/Textual.xcconfig
================================================
#include "../Common/Textual.xcconfig"
#include "Enabled Features.xcconfig"
TEXTUAL_BUNDLE_IDENTIFIER = com.codeux.apps.textual
TEXTUAL_GROUP_CONTAINER_IDENTIFIER = 8482Q6EPL6.com.codeux.apps.textual
TEXTUAL_BUILD_SCHEME_TOKEN = debug
TEXTUAL_EXTENSION_BUILD_SCHEME = Debug
TEXTUAL_FRAMEWORK_BUILD_SCHEME = Release // Frameworks don't have a Debug scheme
TEXTUAL_XPC_SERVICE_BUILD_SCHEME = Debug
================================================
FILE: Configurations/Build/Debug/XPC Service - ICL Extensions.xcconfig
================================================
#include "../Common/Foundation Debug.xcconfig"
#include "Textual.xcconfig"
#include "../Common/XPC Service - ICL Extensions.xcconfig"
================================================
FILE: Configurations/Build/Debug/XPC Service - ICL.xcconfig
================================================
#include "XPC Services.xcconfig"
#include "../Common/XPC Service - ICL.xcconfig"
ICL_EXTENSION_BUILD_SCHEME = Debug
================================================
FILE: Configurations/Build/Debug/XPC Services.xcconfig
================================================
#include "../Common/Foundation Debug.xcconfig"
#include "Textual.xcconfig"
#include "../Common/XPC Services.xcconfig"
================================================
FILE: Configurations/Build/README.md
================================================
TODO: Write a README
================================================
FILE: Configurations/Build/Standard Release/Enabled Features.xcconfig
================================================
// The main project of Textual, its extensions, and its XPC services
// all inherit one of these configuration files to allow them to
// selectively disable code based on which features are enabled.
// These macros that are used to disable and enable the inclusion
// of certain segments of code. Toggling one of these flags does not
// guarantee that the toggled feature will work. These only toggle the code.
// Not add additional resource files that the code may be dependent on.
// To add new feature flags, modify UpdateFeatureFlags.sh
TEXTUAL_BUILT_INSIDE_SANDBOX=1
TEXTUAL_BUILT_WITH_ADVANCED_ENCRYPTION=1
TEXTUAL_BUILT_WITH_LICENSE_MANAGER=1
TEXTUAL_BUILT_WITH_SPARKLE_ENABLED=1
================================================
FILE: Configurations/Build/Standard Release/Textual App.xcconfig
================================================
#include "../Common/Foundation.xcconfig"
#include "Textual.xcconfig"
#include "../Common/Textual App.xcconfig"
CODE_SIGN_ENTITLEMENTS = ${PROJECT_DIR}/Configurations/Sandbox/Standard Release.entitlements
================================================
FILE: Configurations/Build/Standard Release/Textual Extensions.xcconfig
================================================
#include "../Common/Foundation.xcconfig"
#include "Textual.xcconfig"
#include "../Common/Textual Extensions.xcconfig"
================================================
FILE: Configurations/Build/Standard Release/Textual.xcconfig
================================================
#include "../Common/Textual.xcconfig"
#include "Enabled Features.xcconfig"
TEXTUAL_BUNDLE_IDENTIFIER = com.codeux.apps.textual
TEXTUAL_GROUP_CONTAINER_IDENTIFIER = 8482Q6EPL6.com.codeux.apps.textual
TEXTUAL_BUILD_SCHEME_TOKEN = devid
TEXTUAL_EXTENSION_BUILD_SCHEME = Release
TEXTUAL_FRAMEWORK_BUILD_SCHEME = Release
TEXTUAL_XPC_SERVICE_BUILD_SCHEME = Release
================================================
FILE: Configurations/Build/Standard Release/XPC Service - ICL Extensions.xcconfig
================================================
#include "../Common/Foundation.xcconfig"
#include "Textual.xcconfig"
#include "../Common/XPC Service - ICL Extensions.xcconfig"
================================================
FILE: Configurations/Build/Standard Release/XPC Service - ICL.xcconfig
================================================
#include "XPC Services.xcconfig"
#include "../Common/XPC Service - ICL.xcconfig"
ICL_EXTENSION_BUILD_SCHEME = Release
================================================
FILE: Configurations/Build/Standard Release/XPC Services.xcconfig
================================================
#include "../Common/Foundation.xcconfig"
#include "Textual.xcconfig"
#include "../Common/XPC Services.xcconfig"
================================================
FILE: Configurations/ExportArchiveConfiguration.plist
================================================
teamID
8482Q6EPL6
method
developer-id
================================================
FILE: Configurations/Sandbox/Inherited.entitlements
================================================
com.apple.security.app-sandbox
com.apple.security.inherit
================================================
FILE: README.md
================================================
> [!IMPORTANT]
> Textual is no longer being actively maintained. For the life of the project, it only ever had one full time maintainer whom has now moved on to different ventures in their life. To all that have contributed to Textual in some form in the past; be it a suggestion, bug report, pull request, financial support, or some other form of contribvution, you will forever be loved. Thank you so much. Words cannot properly express the gratitude we have for every single user.
# Textual [](https://github.com/Codeux-Software/Textual/blob/master) [](http://www.textualapp.com/mac-app-store)
Textual is a highly customizable app for interacting with Internet Relay Chat (IRC) chatrooms on macOS.
Textual can be customized with styles written in CSS, HTML, and JavaScript; [plugins](https://help.codeux.com/textual/Writing-Plugins.kb) written in Objective-C & Swift, and [scripts](https://help.codeux.com/textual/Writing-Scripts.kb) written in AppleScript (plus many other languages)
Precompiled versions of Textual can be purchased in the [directly from codeux.com](https://www.textualapp.com/).
## Screenshots
[](https://www.codeux.com/textual/private/images/v600media/YosemiteLightFullscreen.png)
[](https://www.codeux.com/textual/private/images/v600media/YosemiteDarkFullscreen.png)
## Resources
- [Homepage](https://codeux.com/textual)
- [Frequently Asked Questions](https://help.codeux.com/textual/Frequently-Asked-Questions.kb)
- [Support](https://help.codeux.com/textual/Support.kb)
- \#textual on irc.libera.chat
- Guides: [Writing Plugins](https://help.codeux.com/textual/Writing-Plugins.kb), [Writing Scripts](https://help.codeux.com/textual/Writing-Scripts.kb)
## Note Regarding Downloading Source Code
Textual is dependent on several other projects to build. This repository is automatically linked against these other projects using what are known as "submodules" — Clicking the "Download ZIP" button to build a copy of Textual will not download a copy of these projects. The source code must be cloned using [Github for Mac](https://mac.github.com/) or by using the following commands in Terminal:
```
git clone https://github.com/Codeux-Software/Textual.git Textual
cd Textual
git submodule update --init --recursive
```
## Note Regarding Code Signing
**DO NOT change the Code Signing Identity setting through Xcode.** Textual uses a configuration file to specify the code signing identity. This allows it to be used across all projects associated with Textual without having to modify each.
**DO** edit the file located at _[Configurations ➜ Build ➜ Code Signing Identity.xcconfig](https://github.com/Codeux-Software/Textual/blob/master/Configurations/Build/Code%20Signing%20Identity.xcconfig)_
**It is HIGHLY DISCOURAGED to turn off code signing.** Certain features rely on the fact that Textual is properly signed and is within a sandboxed environment.
**TEXTUAL DOES NOT REQUIRE A CERTIFICATE ISSUED BY APPLE TO BUILD** which means there is absolutely no reason to turn code signing off.
## Note Regarding Trial Mode
The code which is responsible for licensing paid copies of Textual is in the source code that you download from here.
If you do not have a license key, then set the ``TEXTUAL_BUILT_WITH_LICENSE_MANAGER`` flag to `0` in the `Standard Release` configuration file to disable the inclusion of this code at build time.
## Building Textual
The latest version of Textual requires two things to be built. One is a valid (does not need to be issued by Apple) code signing certificate. The second is an installation of Xcode 10.0 or newer on macOS High Sierra. **Building on anything earlier is not supported because of Swift 4.2 code.**
**DO NOT change the Code Signing Identity setting through Xcode.** Modify the file located at _[Configurations ➜ Build ➜ Code Signing Identity.xcconfig](https://github.com/Codeux-Software/Textual/blob/master/Configurations/Build/Code%20Signing%20Identity.xcconfig)_ instead.
Build Textual using the "Standard Release" build scheme.
## Original Limechat License
Textual began as a fork of [LimeChat](https://github.com/psychs/limechat) in 2010
LimeChat's original license is presented below.
The New BSD License
Copyright (c) 2008 - 2010 Satoshi Nakagawa < psychs AT limechat DOT net >
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
## License for content originating from Textual
Unless stated otherwise by Textual's [Acknowledgements.pdf](Acknowledgements.pdf) document, the license presented below shall govern the distribution of and modifications to; the work hosted by this repository.
Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.
Please see Acknowledgements.pdf for additional information.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of Textual, "Codeux Software, LLC", nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
================================================
FILE: Sources/App/Build Scripts/BuildExtensions.sh
================================================
#!/bin/bash
set -e
echo "Building using architecture: ${ARCHS}"
TEXTUAL_PRODUCT_LOCATION="${TARGET_BUILD_DIR}/${FULL_PRODUCT_NAME}"
TEXTUAL_PRODUCT_BINARY="${TARGET_BUILD_DIR}/${EXECUTABLE_PATH}"
plugins=(
'Caffeine'
'Chat Filter'
'Smiley Converter'
'System Profiler'
'User Insights'
'ZNC Additions'
)
for plugin in "${plugins[@]}"; do
cd "${TEXTUAL_WORKSPACE_DIR}/Sources/Plugins/${plugin}"
xcodebuild -target "$plugin Extension" \
-configuration "${TEXTUAL_EXTENSION_BUILD_SCHEME}" \
ARCHS="${ARCHS}" \
CODE_SIGN_IDENTITY="${CODE_SIGN_IDENTITY}" \
DEVELOPMENT_TEAM="${DEVELOPMENT_TEAM}" \
PROVISIONING_PROFILE_SPECIFIER="" \
TEXTUAL_WORKSPACE_DIR="${TEXTUAL_WORKSPACE_DIR}" \
TEXTUAL_PRODUCT_LOCATION="${TEXTUAL_PRODUCT_LOCATION}" \
TEXTUAL_PRODUCT_BINARY="${TEXTUAL_PRODUCT_BINARY}"
done
exit 0
================================================
FILE: Sources/App/Build Scripts/BuildFrameworks.sh
================================================
#!/bin/bash
set -e
echo "Building using architecture: ${ARCHS}"
CONFIGURATION_BUILD_DIR="${TEXTUAL_WORKSPACE_TEMP_DIR}/SharedBuildProducts-Frameworks"
xcb() {
target=$1
xcodebuild -target "$target" \
-configuration "${TEXTUAL_FRAMEWORK_BUILD_SCHEME}" \
ARCHS="${ARCHS}" \
CODE_SIGN_IDENTITY="${CODE_SIGN_IDENTITY}" \
CONFIGURATION_BUILD_DIR="${CONFIGURATION_BUILD_DIR}" \
DEVELOPMENT_TEAM="${DEVELOPMENT_TEAM}" \
PROVISIONING_PROFILE_SPECIFIER="" \
DWARF_DSYM_FOLDER_PATH="${DWARF_DSYM_FOLDER_PATH}"
}
# Assumes the name and filename of the framework is the same just without spaces.
frameworks=(
'Auto Hyperlinks'
'Encryption Kit'
'Cocoa Extensions'
)
for framework in "${frameworks[@]}"; do
cd "${TEXTUAL_WORKSPACE_DIR}/Frameworks/${framework}/"
xcb "${framework// /}.framework"
done
exit 0
================================================
FILE: Sources/App/Build Scripts/BuildServices.sh
================================================
#!/bin/bash
set -e
echo "Building using architecture: ${ARCHS}"
TEXTUAL_PRODUCT_LOCATION="${TARGET_BUILD_DIR}/${FULL_PRODUCT_NAME}"
TEXTUAL_PRODUCT_BINARY="${TARGET_BUILD_DIR}/${EXECUTABLE_PATH}"
services=(
'Historic Log File Manager'
'Inline Content Loader'
'IRC Remote Connection Manager'
)
for service in "${services[@]}"; do
cd "${TEXTUAL_WORKSPACE_DIR}/XPC Services/${service}/"
xcodebuild -target "$service" \
-configuration "${TEXTUAL_XPC_SERVICE_BUILD_SCHEME}" \
ARCHS="${ARCHS}" \
CODE_SIGN_IDENTITY="${CODE_SIGN_IDENTITY}" \
DEVELOPMENT_TEAM="${DEVELOPMENT_TEAM}" \
PROVISIONING_PROFILE_SPECIFIER="" \
TEXTUAL_WORKSPACE_DIR="${TEXTUAL_WORKSPACE_DIR}" \
TEXTUAL_PRODUCT_LOCATION="${TEXTUAL_PRODUCT_LOCATION}" \
TEXTUAL_PRODUCT_BINARY="${TEXTUAL_PRODUCT_BINARY}"
done
================================================
FILE: Sources/App/Build Scripts/ExportArchive.sh
================================================
#!/bin/sh
set -e
WORKING_PATH="${TEXTUAL_WORKSPACE_TEMP_DIR}/ArchiveTan"
mkdir -p "${WORKING_PATH}"
cd "${WORKING_PATH}"
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
xcodebuild -exportArchive \
-exportOptionsPlist "${TEXTUAL_WORKSPACE_DIR}/Configurations/ExportArchiveConfiguration.plist" \
-archivePath "${ARCHIVE_PATH}" \
-exportPath "${WORKING_PATH}"
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Zip product and send to notary
#
# Format to add notary to keychain:
#
# xcrun notarytool store-credentials "Textual Notary"
# --apple-id ""
# --team-id
# --password ""
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
WORKING_ZIP_PATH="./${FULL_PRODUCT_NAME}.zip"
zip -y -r -X "${WORKING_ZIP_PATH}" "./${FULL_PRODUCT_NAME}/"
xcrun notarytool submit "${WORKING_ZIP_PATH}" \
--keychain-profile "Textual Notary" \
--wait \
--verbose \
--progress
# Remove uploaded product
rm "${WORKING_ZIP_PATH}"
# Stable app
xcrun stapler staple --verbose "./${FULL_PRODUCT_NAME}/"
# Create new zip with stapled app
zip -y -r -X "${WORKING_ZIP_PATH}" "./${FULL_PRODUCT_NAME}/"
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #
# Call `git` after `cd` into working path to make
# sure we are in a directory of a git repository.
GIT_COMMIT_HASH=`git rev-parse --short HEAD`
EXPORT_PATH="${HOME}/Desktop/Textual-${GIT_COMMIT_HASH}"
mkdir -p "${EXPORT_PATH}"
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #
if [ "${TEXTUAL_BUILT_AS_UNIVERSAL_BINARY}" == "1" ]; then
ARCHSPEC_PATH="${EXPORT_PATH}/universal"
else
ARCHSPEC_PATH="${EXPORT_PATH}/intel"
fi
mkdir -p "${ARCHSPEC_PATH}"
ZIP_EXPORT_PATH="${ARCHSPEC_PATH}/Textual.zip"
mv "${WORKING_ZIP_PATH}" "${ZIP_EXPORT_PATH}"
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #
BUNDLE_VERSION_LONG=$(/usr/libexec/PlistBuddy -c "Print \"CFBundleVersion\"" "./${FULL_PRODUCT_NAME}/Contents/Info.plist")
BUNDLE_VERSION_SHORT=$(/usr/libexec/PlistBuddy -c "Print \"CFBundleShortVersionString\"" "./${FULL_PRODUCT_NAME}/Contents/Info.plist")
BUNDLE_MINIMUM_TARGET=$(/usr/libexec/PlistBuddy -c "Print \"LSMinimumSystemVersion\"" "./${FULL_PRODUCT_NAME}/Contents/Info.plist")
echo " ./buildInfo.php
echo " \$current_release_version_short = \"${BUNDLE_VERSION_SHORT}\";" >> ./buildInfo.php
echo " \$current_release_version_long = \"${BUNDLE_VERSION_LONG}\";" >> ./buildInfo.php
echo " \$current_release_version_signature = \"${GIT_COMMIT_HASH}\";" >> ./buildInfo.php
echo " \$current_release_minimum_system_version = \"${BUNDLE_MINIMUM_TARGET}\";" >> buildInfo.php
mv "./buildInfo.php" "${EXPORT_PATH}"
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #
echo "
" > ./buildLog.txt
git log --since='48 hours ago' --pretty=format:' - %s
' >> ./buildLog.txt
echo "
" >> ./buildLog.txt
mv "./buildLog.txt" "${EXPORT_PATH}"
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #
cd "${DWARF_DSYM_FOLDER_PATH}"
DYSM_EXPORT_PATH="${ARCHSPEC_PATH}/Debug symbols.zip"
zip -y -r -X "${DYSM_EXPORT_PATH}" *
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #
rm -rf "${WORKING_PATH}"
exit 0;
================================================
FILE: Sources/App/Build Scripts/MergeSwift.sh
================================================
#!/bin/sh
set -e
#
# Textual and Remote Connection Manager service both use Swift.
# Textual embeds the library and the service will inherit that.
# For some reason, during development, I found that the service
# would not launch because "libswiftSwiftOnoneSupport.dylib"
# was missing in Textual's copy of the library.
#
# Textual and the service both declare -Onone optimization level
# at the same time, so I don't know why one will have it and
# the other does not.
#
# To workaround this issue and any in the future, this script exists.
# This script will find all libswift*.dylb files that aren't in the
# main copy of the library and bring those files in.
#
# TODO: Revisit this when I've had sleep (June 28, 2018)
#
cd "${TARGET_BUILD_DIR}/${CONTENTS_FOLDER_PATH}"
find . -type f -name "libswift*" \
-not -path "./Frameworks/*" \
-not -path "./Resources/*" \
-not -path "*/Resources/libswiftRemoteMirror.dylib" \
-exec cp '{}' ./Frameworks/ \; \
-exec rm '{}' \;
exit 0;
================================================
FILE: Sources/App/Build Scripts/PostprocessSparkle.sh
================================================
#!/bin/bash
set -e
echo "Performing postprocessing on Sparkle framework"
cd "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
rm -rf Sparkle.framework/Versions/B/XPCServices/Downloader.xpc
codesign -f -s "$CODE_SIGN_IDENTITY" -o runtime Sparkle.framework/Versions/B/XPCServices/Installer.xpc
codesign -f -s "$CODE_SIGN_IDENTITY" -o runtime Sparkle.framework/Versions/B/Autoupdate
codesign -f -s "$CODE_SIGN_IDENTITY" -o runtime Sparkle.framework/Versions/B/Updater.app
codesign -f -s "$CODE_SIGN_IDENTITY" -o runtime Sparkle.framework
exit 0
================================================
FILE: Sources/App/Build Scripts/UpdateFeatureFlags.sh
================================================
#!/bin/bash
set -e
cd "${TEXTUAL_WORKSPACE_TEMP_DIR}/Build Headers/"
echo "
/* ANY CHANGES TO THIS FILE WILL NOT BE SAVED AND WILL NOT BE COMMITTED */
" > _FeatureFlags.h
featureNames=("TEXTUAL_BUILT_INSIDE_SANDBOX"
"TEXTUAL_BUILT_WITH_SPARKLE_ENABLED"
"TEXTUAL_BUILT_WITH_LICENSE_MANAGER"
"TEXTUAL_BUILT_WITH_ADVANCED_ENCRYPTION"
"TEXTUAL_BUILT_FOR_APP_STORE_DISTRIBUTION"
"TEXTUAL_BUILT_AS_UNIVERSAL_BINARY")
for feature in "${featureNames[@]}"; do
featureValue="${!feature}"
if [ -n "${featureValue}" ]; then
echo "#define ${feature} ${featureValue}" >> _FeatureFlags.h
else
echo "#define ${feature} 0" >> _FeatureFlags.h
fi
done
if cmp -s "FeatureFlags.h" "_FeatureFlags.h"; then
echo "The feature flags file hasn't changed. Not deploying."
rm "_FeatureFlags.h"
else
# Force flag is used on rm to avoid error for missing file
rm -f "FeatureFlags.h"
mv "_FeatureFlags.h" "FeatureFlags.h"
fi
# ------ #
# Exit with success
exit 0;
================================================
FILE: Sources/App/Build Scripts/UpdateVersionInfo.sh
================================================
#!/bin/sh
set -e
cd "${TEXTUAL_WORKSPACE_TEMP_DIR}/"
# Make a copy of the Info.plist file in the .tmp folder
# This will be the Info.plist file manipulated with the version
# information that is generated below.
infoPlistSource="${PROJECT_DIR}/Resources/Property Lists/Application Properties/Info.plist"
infoPlistTarget="${TEXTUAL_WORKSPACE_TEMP_DIR}/Info.plist"
if [ ! -f "${infoPlistTarget}" ] || [ "${infoPlistTarget}" -ot "${infoPlistSource}" ]; then
echo "Step 1: Info.plist file doesn't exist and/or is oudated. Performing copy."
# Copy with -p flag to preserve modification time
cp -p "${infoPlistSource}" "${infoPlistTarget}"
else
echo "Step 1: Info.plist file hasn't changed."
fi
# Write the version information to the Info.plist file.
# The build version is the date of the last commit in git.
gitBundle=`which git`
if [ -z "${gitBundle}" ]; then
bundleVersionNew="000000.00"
else
gitDateOfLastCommit=`"${gitBundle}" log -n1 --format="%at"`
bundleVersionNew=`/bin/date -u -r "${gitDateOfLastCommit}" "+%y%m%d.%H"`
fi;
bundleVersionOld=$(/usr/libexec/PlistBuddy -c "Print \"CFBundleVersion\"" Info.plist)
if [ "${bundleVersionOld}" != "${bundleVersionNew}" ]; then
echo "Step 2: Writing version: New ('${bundleVersionNew}'), Old ('${bundleVersionOld}')"
/usr/libexec/PlistBuddy -c "Set \"CFBundleVersion\" \"${bundleVersionNew}\"" Info.plist
else
echo "Step 2: The version hasn't changed."
fi
# ------ #
# Gather the information necessary for building Textual's BuildConfig.h
# header. This header file gives various section of the code base version
# information so it does not need to constantly access the Info.plist file.
bundleVersionShort=$(/usr/libexec/PlistBuddy -c "Print \"CFBundleShortVersionString\"" Info.plist)
mkdir -p "./Build Headers"
cd "./Build Headers"
echo "
/* ANY CHANGES TO THIS FILE WILL NOT BE SAVED AND WILL NOT BE COMMITTED */
#define TXBundleBuildProductName @\"${PRODUCT_NAME}\"
#define TXBundleBuildProductIdentifier @\"${PRODUCT_BUNDLE_IDENTIFIER}\"
#define TXBundleBuildProductIdentifierCString \"${PRODUCT_BUNDLE_IDENTIFIER}\"
#define TXBundleBuildGroupContainerIdentifier @\"${TEXTUAL_GROUP_CONTAINER_IDENTIFIER}\"
#define TXBundleBuildVersion @\"${bundleVersionNew}\"
#define TXBundleBuildVersionShort @\"${bundleVersionShort}\"
#define TXBundleBuildScheme @\"${TEXTUAL_BUILD_SCHEME_TOKEN}\"
" > _BuildConfig.h
if [ -z "$CODE_SIGN_IDENTITY" ]; then
echo "#define TXBundleBuiltWithoutCodeSigning 1" >> _BuildConfig.h
fi
if cmp -s "BuildConfig.h" "_BuildConfig.h"; then
echo "Step 3: The build configuration file hasn't changed. Not deploying."
rm "_BuildConfig.h"
else
# Force flag is used on rm to avoid error for missing file
rm -f "BuildConfig.h"
mv "_BuildConfig.h" "BuildConfig.h"
fi
# ------ #
# Compile list of enabled features
exec "${PROJECT_DIR}/Build Scripts/UpdateFeatureFlags.sh" > "${TEXTUAL_WORKSPACE_TEMP_DIR}/Script-Logs/UpdateFeatureFlags.txt"
# ------ #
# Exit with success
exit 0;
================================================
FILE: Sources/App/Classes/Controllers/TXAppearance.m
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2018 - 2020 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual and/or Codeux Software, nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "NSObjectHelperPrivate.h"
#import "TPCPreferencesLocal.h"
#import "TXAppearance.h"
NS_ASSUME_NONNULL_BEGIN
NSString * const TXApplicationAppearanceChangedNotification = @"TXApplicationAppearanceChangedNotification";
NSString * const TXSystemAppearanceChangedNotification = @"TXSystemAppearanceChangedNotification";
@interface TXAppearancePropertyCollection ()
@property (nonatomic, copy, readwrite) NSString *appearanceName;
@property (nonatomic, assign, readwrite) TXAppearanceType appearanceType;
@property (nonatomic, assign, readwrite) BOOL isDarkAppearance;
@property (nonatomic, assign, readwrite) TXAppKitAppearanceTarget appKitAppearanceTarget;
@end
@interface TXAppearance ()
@property (nonatomic, strong, readwrite) TXAppearancePropertyCollection *properties;
@end
@implementation TXAppearance
#pragma mark -
#pragma mark Initialization
- (instancetype)init
{
if ((self = [super init])) {
[self prepareInitialState];
return self;
}
return nil;
}
- (void)prepareInitialState
{
[self updateAppearance];
[RZWorkspaceNotificationCenter() addObserver:self
selector:@selector(accessibilityDisplayOptionsDidChange:)
name:NSWorkspaceAccessibilityDisplayOptionsDidChangeNotification
object:nil];
[NSApp addObserver:self forKeyPath:@"effectiveAppearance" options:NSKeyValueObservingOptionNew context:NULL];
}
- (void)prepareForApplicationTermination
{
LogToConsoleTerminationProgress("Removing appearance change observers");
[RZNotificationCenter() removeObserver:self];
[NSApp removeObserver:self forKeyPath:@"effectiveAppearance"];
}
#pragma mark -
#pragma mark Properties
+ (nullable NSString *)appearanceNameForType:(TXAppearanceType)type
{
switch (type) {
case TXAppearanceTypeBigSurLight:
{
return @"BigSurLight";
}
case TXAppearanceTypeBigSurDark:
{
return @"BigSurDark";
}
default:
{
return nil;
}
}
}
#pragma mark -
#pragma mark Notifications
- (void)observeValueForKeyPath:(nullable NSString *)keyPath ofObject:(nullable id)object change:(nullable NSDictionary *)change context:(nullable void *)context
{
if ([keyPath isEqualToString:@"effectiveAppearance"]) {
[self applicationAppearanceChanged];
}
}
- (void)applicationAppearanceChanged
{
/* Wait until next pass of the run loop to perform
update because the effective appearance may not
be propagated to all subviews when this is called. */
XRPerformBlockAsynchronouslyOnMainQueue(^{
[self updateAppearanceBySystemChange];
});
}
- (void)systemColorsDidChange:(NSNotification *)aNote
{
[self updateAppearanceBySystemChange];
}
- (void)accessibilityDisplayOptionsDidChange:(NSNotification *)aNote
{
[self updateAppearanceBySystemChange];
}
- (void)updateAppearance
{
[self updateAppearanceBySystemChange:NO];
}
- (void)updateAppearanceBySystemChange
{
[self updateAppearanceBySystemChange:YES];
}
- (void)updateAppearanceBySystemChange:(BOOL)systemChanged
{
TXAppearanceType appearanceType = TXAppearanceTypeBigSurLight;
TXPreferredAppearance preferredAppearance = [TPCPreferences appearance];
/* Determine user's preference */
switch (preferredAppearance) {
case TXPreferredAppearanceInherited:
{
if ([TXAppearancePropertyCollection systemWideDarkModeEnabled]) {
appearanceType = TXAppearanceTypeBigSurDark;
}
break;
}
case TXPreferredAppearanceDark:
{
appearanceType = TXAppearanceTypeBigSurDark;
break;
}
default:
{
break;
}
}
BOOL isAppearanceDark = (appearanceType == TXAppearanceTypeBigSurDark);
/* Determine best appearance inheritance approach */
/* Before Mojave, appearance needs to be applied to every view.
After Mojave, views properly inherit the appearance of the parent
window or the system. If the user selects a specific appearance,
then we apply that to the parent window on Mojave and later to
allow views to inherit that. If the user selects the system
appearance, then we apply nothing and allow it to be inherited
from the system. */
TXAppKitAppearanceTarget appKitAppearanceTarget = TXAppKitAppearanceTargetNone;
if (preferredAppearance != TXPreferredAppearanceInherited) {
appKitAppearanceTarget = TXAppKitAppearanceTargetWindow;
}
/* Test for changes */
TXAppearancePropertyCollection *oldProperties = self.properties;
BOOL changeAppearance = (oldProperties == nil ||
(oldProperties.appearanceType != appearanceType) ||
(oldProperties.appKitAppearanceTarget != appKitAppearanceTarget));
if (changeAppearance == NO)
{
/* Even if the desired appearance hasn't changed, we still
signal views to perform selection update so that vibrant
views can draw correctly when the system changes. */
if (systemChanged == NO) {
return;
}
}
else
{
/* When appearance changes as a result of a system change, then we
treat it as an application change as that's more specialized. */
systemChanged = NO;
}
/* Assign new properties */
TXAppearancePropertyCollection *newProperties = [TXAppearancePropertyCollection new];
newProperties.appearanceName = [self.class appearanceNameForType:appearanceType];
newProperties.appearanceType = appearanceType;
newProperties.isDarkAppearance = isAppearanceDark;
newProperties.appKitAppearanceTarget = appKitAppearanceTarget;
self.properties = newProperties;
/* Notify observers */
if (systemChanged == NO) {
[self notifyApplicationAppearanceChanged];
} else {
[self notifySystemAppearanceChanged];
}
}
- (void)notifyApplicationAppearanceChanged
{
[RZNotificationCenter() postNotificationName:TXApplicationAppearanceChangedNotification object:self];
}
- (void)notifySystemAppearanceChanged
{
[RZNotificationCenter() postNotificationName:TXSystemAppearanceChangedNotification object:self];
}
@end
#pragma mark -
#pragma mark Property Collection
@implementation TXAppearancePropertyCollection
- (nullable NSAppearance *)appKitAppearance
{
if (self.appKitAppearanceTarget == TXAppKitAppearanceTargetNone) {
return nil;
}
if (self.isDarkAppearance) {
return [self.class appKitDarkAppearance];
} else {
return [self.class appKitLightAppearance];
}
}
- (NSString *)shortAppearanceDescription
{
if (self.isDarkAppearance == NO) {
return @"light";
} else {
return @"dark";
}
}
+ (BOOL)systemWideDarkModeEnabled
{
return ([[NSApp effectiveAppearance] bestMatchFromAppearancesWithNames:@[NSAppearanceNameDarkAqua]] != nil);
}
+ (nullable NSAppearance *)appKitDarkAppearance
{
return [NSAppearance appearanceNamed:NSAppearanceNameDarkAqua];
}
+ (nullable NSAppearance *)appKitLightAppearance
{
return [NSAppearance appearanceNamed:NSAppearanceNameAqua];
}
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Controllers/TXApplication.m
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "TDCAlert.h"
#import "TLOLocalization.h"
#import "TPCApplicationInfo.h"
#import "TXApplicationPrivate.h"
NS_ASSUME_NONNULL_BEGIN
@implementation TXApplication
+ (BOOL)checkForOtherCopiesOfTextualRunning
{
pid_t ourProcessIdentifier = [[NSProcessInfo processInfo] processIdentifier];
for (NSRunningApplication *application in RZWorkspace().runningApplications) {
if ([application.bundleIdentifier isEqualToString:@"com.codeux.apps.textual"] ||
[application.bundleIdentifier isEqualToString:@"com.codeux.apps.textual-mas"] ||
[application.bundleIdentifier isEqualToString:@"com.codeux.irc.textual5"])
{
if (application.processIdentifier == ourProcessIdentifier) {
continue;
}
BOOL continueLaunch = [TDCAlert modalAlertWithMessage:TXTLS(@"Prompts[kx4-q8]")
title:TXTLS(@"Prompts[hcb-3i]")
defaultButton:TXTLS(@"Prompts[mvh-ms]")
alternateButton:TXTLS(@"Prompts[99q-gg]")];
return continueLaunch;
}
}
return YES;
}
- (void)sendEvent:(NSEvent *)event
{
BOOL performedCustomEvent = [self performedCustomKeyboardEvent:event];
if (performedCustomEvent) {
return;
}
[super sendEvent:event];
}
- (BOOL)performedCustomKeyboardEvent:(NSEvent *)event
{
if (event.type != NSEventTypeKeyDown) {
return NO;
}
NSWindow *keyWindow = self.keyWindow;
if ([self sendCustomKeyboardEvent:event toObject:keyWindow]) {
return YES;
}
NSResponder *firstResponder = keyWindow.firstResponder;
if ([self sendCustomKeyboardEvent:event toObject:firstResponder]) {
return YES;
}
return NO;
}
- (BOOL)sendCustomKeyboardEvent:(NSEvent *)event toObject:(nullable id)object
{
if (object == nil) {
return NO;
}
if ([object respondsToSelector:@selector(performedCustomKeyboardEvent:)]) {
if ([(id)object performedCustomKeyboardEvent:event]) {
return YES;
}
}
return NO;
}
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Controllers/TXGlobalModels.m
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import
#import "TLOLocalization.h"
#import "TXGlobalModels.h"
NS_ASSUME_NONNULL_BEGIN
#pragma mark -
#pragma mark Time
NSString * _Nullable TXFormattedTimestamp(NSDate *date, NSString *format)
{
NSCParameterAssert(date != nil);
NSCParameterAssert(format != nil);
time_t global = (time_t)date.timeIntervalSince1970;
const size_t outputBufferSize = 256;
char outputBuffer[(outputBufferSize + 1)];
struct tm *localTime = localtime(&global);
if (strftime(outputBuffer, outputBufferSize, format.UTF8String, localTime) == 0) {
return nil;
}
return @(outputBuffer);
}
NSString * _Nullable TXHumanReadableTimeInterval(NSTimeInterval dateInterval, BOOL shortValue, NSCalendarUnit orderMatrix)
{
/* Default what we will return */
if (orderMatrix == 0) {
orderMatrix = (NSCalendarUnitYear |
NSCalendarUnitMonth |
NSCalendarUnitDay |
NSCalendarUnitHour |
NSCalendarUnitMinute |
NSCalendarUnitSecond);
}
/* Convert calendar units to a text rep */
NSMutableArray *units = [NSMutableArray arrayWithCapacity:6];
if (orderMatrix & NSCalendarUnitYear) {
[units addObject:@(NSCalendarUnitYear)];
}
if (orderMatrix & NSCalendarUnitMonth) {
[units addObject:@(NSCalendarUnitMonth)];
}
if (orderMatrix & NSCalendarUnitDay) {
[units addObject:@(NSCalendarUnitDay)];
}
if (orderMatrix & NSCalendarUnitHour) {
[units addObject:@(NSCalendarUnitHour)];
}
if (orderMatrix & NSCalendarUnitMinute) {
[units addObject:@(NSCalendarUnitMinute)];
}
if (orderMatrix & NSCalendarUnitSecond) {
[units addObject:@(NSCalendarUnitSecond)];
}
/* Build compare information */
NSCalendar *systemCalendar = [NSCalendar currentCalendar];
NSDate *date1 = [NSDate date];
NSDate *date2 = [NSDate dateWithTimeIntervalSinceNow:dateInterval];
/* Perform comparison */
NSDateComponents *breakdownInfo = [systemCalendar components:orderMatrix fromDate:date1 toDate:date2 options:0];
if (breakdownInfo == nil) {
return nil;
}
NSMutableString *returnResult = nil;
for (NSNumber *unit in units) {
NSInteger unitValue = [breakdownInfo valueForComponent:unit.unsignedIntegerValue];
/* If results isn't zero, we show it */
if (unitValue == 0) {
continue;
}
if (unitValue < 0) {
unitValue *= (-1);
}
NSString *languageKey = nil;
if (unitValue == 1) { // plurals
languageKey = [NSString stringWithFormat:@"fko-64-%@", unit];
} else {
languageKey = [NSString stringWithFormat:@"eoq-pr-%@", unit];
}
/* shortValue returns only the first time component */
if (shortValue) {
return [NSString stringWithFormat:@"%ld %@", unitValue, TXTLS(languageKey)];
}
if (returnResult == nil) {
returnResult = [NSMutableString string];
}
if (unit == units.lastObject) {
[returnResult appendFormat:@"%ld %@", unitValue, TXTLS(languageKey)];
} else {
[returnResult appendFormat:@"%ld %@, ", unitValue, TXTLS(languageKey)];
}
}
if (returnResult.length > 0) {
return [returnResult copy];
}
/* Return "0 seconds" when there are no results. */
return [NSString stringWithFormat:@"0 %@", TXTLS(@"BasicLanguage[eoq-pr-128]")];
}
NSString * _Nullable TXFormatDateLongStyle(id dateObject, BOOL relativeOutput)
{
return TXFormatDate(dateObject, NSDateFormatterLongStyle, NSDateFormatterLongStyle, relativeOutput);
}
NSString * _Nullable TXFormatDate(id dateObject, NSDateFormatterStyle dateStyle, NSDateFormatterStyle timeStyle, BOOL relativeOutput)
{
NSCParameterAssert(dateObject != nil);
NSDateFormatter *dateFormatter = [NSDateFormatter new];
dateFormatter.doesRelativeDateFormatting = relativeOutput;
dateFormatter.lenient = YES;
dateFormatter.dateStyle = dateStyle;
dateFormatter.timeStyle = timeStyle;
NSString *resultString = nil;
if ([dateObject isKindOfClass:[NSString class]]) {
resultString = [dateFormatter stringForObjectValue:dateObject];
} else if ([dateObject isKindOfClass:[NSDate class]]) {
resultString = [dateFormatter stringFromDate:dateObject];
}
return resultString;
}
NSDateFormatter *TXSharedISOStandardDateFormatter(void)
{
static NSDateFormatter *_isoStandardDateFormatter = nil;
if (_isoStandardDateFormatter == nil) {
NSDateFormatter *dateFormatter = [NSDateFormatter new];
dateFormatter.locale = [NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"];
dateFormatter.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"UTC"];
dateFormatter.dateFormat = @"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"; //2011-10-19T16:40:51.620Z
_isoStandardDateFormatter = dateFormatter;
}
return _isoStandardDateFormatter;
}
#pragma mark -
#pragma mark Misc
NSUInteger TXRandomNumber(u_int32_t maximum)
{
return arc4random_uniform(maximum);
}
NSString *TXFormattedNumber(NSInteger number)
{
return [NSNumberFormatter localizedStringFromNumber:@(number) numberStyle:NSNumberFormatterDecimalStyle];
}
NSComparator NSDefaultComparator = ^(id object1, id object2)
{
return [object1 compare:object2];
};
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Controllers/TXMasterController.m
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2008 - 2010 Satoshi Nakagawa
* Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "BuildConfig.h"
#import "NSObjectHelperPrivate.h"
#import "OELReachability.h"
#import "TDCAlert.h"
#import "TLOEncryptionManagerPrivate.h"
#import "TLOLicenseManagerPrivate.h"
#import "TLOLocalization.h"
#import "TLOSpeechSynthesizerPrivate.h"
#import "THOPluginManagerPrivate.h"
#import "TDCLicenseManagerDialogPrivate.h"
#import "TVCLogControllerHistoricLogFilePrivate.h"
#import "TVCLogControllerInlineMediaServicePrivate.h"
#import "TVCLogControllerOperationQueuePrivate.h"
#import "TVCMainWindowPrivate.h"
#import "IRCChannelPrivate.h"
#import "IRCChannelMemberListPrivate.h"
#import "IRCCommandIndexPrivate.h"
#import "IRCExtrasPrivate.h"
#import "IRCWorldPrivate.h"
#import "TPCApplicationInfoPrivate.h"
#import "TPCPreferencesLocalPrivate.h"
#import "TPCPreferencesUserDefaults.h"
#import "TPCResourceManagerPrivate.h"
#import "TPCSandboxMigrationPrivate.h"
#import "TPCThemeControllerPrivate.h"
#import "TXMenuControllerPrivate.h"
#import "TXWindowControllerPrivate.h"
#import "TXMasterControllerPrivate.h"
#import "IRCClient.h"
#if TEXTUAL_BUILT_WITH_SPARKLE_ENABLED == 1
#import
#endif
NS_ASSUME_NONNULL_BEGIN
@interface TXMasterController ()
@property (nonatomic, strong, readwrite) IRCWorld *world;
@property (nonatomic, assign, readwrite) BOOL debugModeIsOn;
@property (nonatomic, assign, readwrite) BOOL ghostModeIsOn;
@property (nonatomic, assign, readwrite) BOOL applicationIsActive;
@property (nonatomic, assign, readwrite) BOOL applicationIsLaunched;
@property (nonatomic, assign, readwrite) BOOL applicationIsTerminating;
@property (nonatomic, assign, readwrite) BOOL applicationIsChangingActiveState;
@property (readonly) BOOL isSafeToPerformApplicationTermination;
@property (nonatomic, assign, readwrite) BOOL terminateHistoricLogSaveFinished;
@property (nonatomic, strong, readwrite) IBOutlet TVCMainWindow *mainWindow;
@property (nonatomic, weak, readwrite) IBOutlet TXMenuController *menuController;
@property (nonatomic, assign) NSUInteger applicationLaunchRemainder;
#if TEXTUAL_BUILT_WITH_SPARKLE_ENABLED == 1
@property (nonatomic, strong, readwrite) SPUStandardUpdaterController *updateController;
#endif
@end
@implementation TXMasterController
#pragma mark -
#pragma mark Initialization
- (instancetype)init
{
if ((self = [super init])) {
[NSObject setGlobalMasterControllerClassReference:self];
[self prepareInitialState];
return self;
}
return nil;
}
- (void)prepareInitialState
{
LogToConsoleSetDefaultSubsystemToMainBundle(@"General");
NSUInteger keyboardKeys = ([NSEvent modifierFlags] & NSEventModifierFlagDeviceIndependentFlagsMask);
if ((keyboardKeys & NSEventModifierFlagControl) == NSEventModifierFlagControl) {
self.debugModeIsOn = YES;
LogToConsoleInfo("Launching in debug mode");
}
#if defined(DEBUG)
self.ghostModeIsOn = YES; // Do not use auto connect during debug
#else
if ((keyboardKeys & NSEventModifierFlagShift) == NSEventModifierFlagShift) {
self.ghostModeIsOn = YES;
LogToConsoleInfo("Launching without auto connecting to the configured servers");
}
#endif
}
- (void)awakeFromNib
{
static BOOL _awakeFromNibCalled = NO;
if (_awakeFromNibCalled == NO) {
_awakeFromNibCalled = YES;
[self _awakeFromNib];
}
}
- (void)_awakeFromNib
{
/* Migrate files and preferences */
[TPCSandboxMigration migrateResources];
/* Initialize preferences */
[TPCPreferences initPreferences];
/* Call shared instance to warm it */
[TXSharedApplication sharedAppearance];
/* We wait until -awakeFromNib to wake the window so that the menu
controller created by the main nib has time to load. */
[RZMainBundle() loadNibNamed:@"TVCMainWindow" owner:self topLevelObjects:nil];
}
- (void)applicationWakeStepOne
{
self.world = [IRCWorld new];
}
- (void)applicationWakeStepTwo
{
[IRCCommandIndex populateCommandIndex];
[self prepareNetworkReachabilityNotifier];
[RZWorkspaceNotificationCenter() addObserver:self selector:@selector(computerDidWakeUp:) name:NSWorkspaceDidWakeNotification object:nil];
[RZWorkspaceNotificationCenter() addObserver:self selector:@selector(computerWillSleep:) name:NSWorkspaceWillSleepNotification object:nil];
[RZWorkspaceNotificationCenter() addObserver:self selector:@selector(computerWillPowerOff:) name:NSWorkspaceWillPowerOffNotification object:nil];
[RZWorkspaceNotificationCenter() addObserver:self selector:@selector(computerScreenDidWake:) name:NSWorkspaceScreensDidWakeNotification object:nil];
[RZWorkspaceNotificationCenter() addObserver:self selector:@selector(computerScreenWillSleep:) name:NSWorkspaceScreensDidSleepNotification object:nil];
[RZNotificationCenter() addObserver:self selector:@selector(pluginsFinishedLoading:) name:THOPluginManagerFinishedLoadingPluginsNotification object:nil];
[RZAppleEventManager() setEventHandler:self andSelector:@selector(handleURLEvent:withReplyEvent:) forEventClass:kInternetEventClass andEventID:kAEGetURL];
[NSColorPanel setPickerMask:(NSColorPanelRGBModeMask | NSColorPanelGrayModeMask | NSColorPanelColorListModeMask | NSColorPanelWheelModeMask | NSColorPanelCrayonModeMask)];
[[NSColorPanel sharedColorPanel] setShowsAlpha:YES];
XRPerformBlockAsynchronouslyOnGlobalQueueWithPriority(^{
[TPCResourceManager copyResourcesToApplicationSupportFolder];
}, DISPATCH_QUEUE_PRIORITY_BACKGROUND);
/* We want to guarantee some specific things happen before the
app is considered "launched" and ready to use. This property
counts down once each task completes and once it reaches 0,
then the app is considered launched. */
/* 1 is default value because we want plugins to be loaded
before we are finished launching. */
[self addObserver:self forKeyPath:@"applicationLaunchRemainder" options:NSKeyValueObservingOptionNew context:NULL];
self.applicationLaunchRemainder = 1;
#if TEXTUAL_BUILT_WITH_LICENSE_MANAGER == 1
[self prepareLicenseManager];
#endif
[self prepareThirdPartyServices];
/* Load plugins last so that -applicationDidFinishLaunching is posted
only once they have loaded and everything else has been setup. */
[sharedPluginManager() loadPlugins];
}
- (void)observeValueForKeyPath:(nullable NSString *)keyPath ofObject:(nullable id)object change:(nullable NSDictionary *)change context:(nullable void *)context
{
if ([keyPath isEqualToString:@"applicationLaunchRemainder"]) {
if (self.applicationLaunchRemainder == 0) {
[self applicationDidFinishLaunching];
}
}
}
- (void)pluginsFinishedLoading:(NSNotification *)notification
{
self.applicationLaunchRemainder -= 1;
}
#pragma mark -
#pragma mark Services
- (void)prepareThirdPartyServiceSparkleFramework
{
#if TEXTUAL_BUILT_WITH_SPARKLE_ENABLED == 1
SPUStandardUpdaterController *controller =
[[SPUStandardUpdaterController alloc] initWithStartingUpdater:NO
updaterDelegate:(id )self
userDriverDelegate:nil];
self.updateController = controller;
SPUUpdater *updater = controller.updater;
if ([updater respondsToSelector:@selector(clearFeedURLFromUserDefaults)]) {
[updater performSelector:@selector(clearFeedURLFromUserDefaults)];
} else {
[RZUserDefaults() removeObjectForKey:@"SUFeedURL"];
}
NSError *error;
(void)[updater startUpdater:&error];
if (error) {
LogToConsoleError("Sparkle failed to start updater: %{public}@", error.description);
}
#endif
}
- (void)prepareThirdPartyServices
{
[self prepareThirdPartyServiceSparkleFramework];
}
- (void)prepareNetworkReachabilityNotifier
{
OELReachability *notifier = [TXSharedApplication sharedNetworkReachabilityNotifier];
notifier.reachableBlock = ^(OELReachability *reachability) {
[self.world noteReachabilityChanged:YES];
};
notifier.unreachableBlock = ^(OELReachability *reachability) {
[self.world noteReachabilityChanged:NO];
};
[notifier startNotifier];
}
#if TEXTUAL_BUILT_WITH_LICENSE_MANAGER == 1
- (void)prepareLicenseManager
{
TLOLicenseManagerSetup();
[[TXSharedApplication sharedLicenseManagerDialog] applicationDidFinishLaunching];
}
#endif
#pragma mark -
#pragma mark NSApplication Delegate
- (void)applicationWillFinishLaunching:(NSNotification *)notification
{
/* UserNotifications.framework wants delegation set before app has
finished launching. A simple access to the singleton will set this
for us which we can just do here. */
LogToConsoleDebug("Preparing notification controller singeton: %@",
sharedNotificationController().description);
}
- (void)applicationDidFinishLaunching
{
[self removeObserver:self forKeyPath:@"applicationLaunchRemainder"];
self.applicationIsLaunched = YES;
if ([self.mainWindow reloadLoadingScreen]) {
[self.world autoConnectAfterWakeup:NO];
}
[self.mainWindow maybeToggleFullscreenAfterLaunch];
}
- (void)applicationWillResignActive:(NSNotification *)notification
{
self.applicationIsChangingActiveState = YES;
}
- (void)applicationWillBecomeActive:(NSNotification *)notification
{
self.applicationIsChangingActiveState = YES;
}
- (void)applicationDidResignActive:(NSNotification *)notification
{
self.applicationIsActive = NO;
self.applicationIsChangingActiveState = NO;
}
- (void)applicationDidBecomeActive:(NSNotification *)notification
{
self.applicationIsActive = YES;
self.applicationIsChangingActiveState = NO;
}
- (BOOL)applicationShouldHandleReopen:(NSApplication *)sender hasVisibleWindows:(BOOL)flag
{
if (self.applicationIsTerminating) {
return NO;
}
[self.mainWindow makeKeyAndOrderFront:nil];
return YES;
}
- (BOOL)applicationShouldOpenUntitledFile:(NSApplication *)sender
{
if (self.applicationIsTerminating) {
return NO;
}
[self.mainWindow makeKeyAndOrderFront:nil];
return YES;
}
- (BOOL)applicationSupportsSecureRestorableState:(NSApplication *)sender
{
/* This will have no effect on our app. Implement to suppress warning in console. */
return YES;
}
#pragma mark -
#pragma mark NSApplication Terminate Procedure
- (NSMenu *)applicationDockMenu:(NSApplication *)sender
{
return self.menuController.dockMenu;
}
- (BOOL)queryTerminate
{
if (self.applicationIsTerminating) {
LogToConsoleTerminationProgress("Termination is already in progress");
return YES;
}
if ([TPCPreferences confirmQuit] == NO) {
return YES;
}
BOOL stillConnected = NO;
for (IRCClient *u in worldController().clientList) {
if (u.isConnecting || u.isConnected) {
stillConnected = YES;
}
}
if (stillConnected) {
BOOL result = [TDCAlert modalAlertWithMessage:TXTLS(@"Prompts[77u-vp]")
title:TXTLS(@"Prompts[6vj-2p]")
defaultButton:TXTLS(@"Prompts[1bf-k0]")
alternateButton:TXTLS(@"Prompts[qso-2g]")];
LogToConsoleTerminationProgress("Perform termination: %{BOOL}d", result);
return result;
}
return YES;
}
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
{
if ([self queryTerminate] == NO) {
return NSTerminateCancel;
}
XRPerformBlockAsynchronouslyOnMainQueue(^{
[self performApplicationTerminationStepOne];
});
return NSTerminateLater;
}
- (BOOL)isSafeToPerformApplicationTermination
{
/* Clients are still disconnecting */
BOOL condition1 = (self.terminatingClientCount == 0);
/* Core Data is saving */
BOOL condition2 = (TVCLogControllerHistoricLogSharedInstance().isSaving == NO &&
self.terminateHistoricLogSaveFinished);
LogToConsoleTerminationProgress("Conditions: %{BOOL}d %{BOOL}d", condition1, condition2);
return (condition1 && condition2);
}
- (void)performApplicationTerminationStepOne
{
LogToConsoleTerminationProgress("Step one entry");
self.applicationIsTerminating = YES;
[[TXSharedApplication sharedAppearance] prepareForApplicationTermination];
[self.mainWindow prepareForApplicationTermination];
LogToConsoleTerminationProgress("Giving up shared application delegation");
[[NSApplication sharedApplication] setDelegate:nil];
LogToConsoleTerminationProgress("Removing workspace notification center observer");
[RZWorkspaceNotificationCenter() removeObserver:self];
LogToConsoleTerminationProgress("Removing shared notification center observer");
[RZNotificationCenter() removeObserver:self];
LogToConsoleTerminationProgress("Removing AppleScript event observer");
[RZAppleEventManager() removeEventHandlerForEventClass:kInternetEventClass andEventID:kAEGetURL];
LogToConsoleTerminationProgress("Stopping reachability notifier");
[[TXSharedApplication sharedNetworkReachabilityNotifier] stopNotifier];
LogToConsoleTerminationProgress("Stopping speech synthesizer");
[[TXSharedApplication sharedSpeechSynthesizer] setIsStopped:YES];
[TVCLogControllerInlineMediaSharedInstance() prepareForApplicationTermination];
#if TEXTUAL_BUILT_WITH_ADVANCED_ENCRYPTION == 1
[sharedEncryptionManager() prepareForApplicationTermination];
#endif
[self.menuController prepareForApplicationTermination];
[self performApplicationTerminationStepTwo];
}
- (void)performApplicationTerminationStepTwo
{
if (self.applicationIsTerminating == NO) {
return;
}
LogToConsoleTerminationProgress("Step two entry");
self.terminatingClientCount = worldController().clientCount;
[self.world prepareForApplicationTermination];
if (self.isSafeToPerformApplicationTermination) {
[self performApplicationTerminationStepThree];
return;
}
/* We want certain things to 100% happen before the app completely closes.
This block that is performed below loops until all these actions are completed.
Notable actions: gracefully leaving IRC, saving historic logs, etc. */
XRPerformBlockAsynchronouslyOnGlobalQueueWithPriority(^{
do {
/* We wait until this value reaches zero so that
view controllers had the chance to perform any
changes they want to historic log. */
if (self.terminatingClientCount == 0) {
[TVCLogControllerHistoricLogSharedInstance() prepareForApplicationTermination];
self.terminateHistoricLogSaveFinished = YES;
}
/* Sleep a little bit so we aren't looping a lot. */
[NSThread sleepForTimeInterval:0.5];
} while (self.isSafeToPerformApplicationTermination == NO);
XRPerformBlockAsynchronouslyOnMainQueue(^{
[self performApplicationTerminationStepThree];
});
}, DISPATCH_QUEUE_PRIORITY_HIGH);
}
- (void)performApplicationTerminationStepThree
{
if (self.applicationIsTerminating == NO) {
return;
}
LogToConsoleTerminationProgress("Step three entry");
if (self.skipTerminateSave == NO) {
LogToConsoleTerminationProgress("Saving IRC world");
[self.world save];
}
LogToConsoleTerminationProgress("Suspending member list dispatch queue");
[IRCChannelMemberList suspendMemberListSerialQueues];
LogToConsoleTerminationProgress("Unloading plugins");
[sharedPluginManager() unloadPlugins];
[windowController() prepareForApplicationTermination];
[themeController() prepareForApplicationTermination];
LogToConsoleTerminationProgress("Saving running internal");
[TPCApplicationInfo saveTimeIntervalSinceApplicationInstall];
LogToConsoleTerminationProgress("Terminate");
[NSApp replyToApplicationShouldTerminate:YES];
}
- (void)terminateGracefully
{
self.applicationIsTerminating = YES;
[RZSharedApplication() terminate:nil];
}
#pragma mark -
#pragma mark NSWorkspace Notifications
- (void)handleURLEvent:(NSAppleEventDescriptor *)event
withReplyEvent:(NSAppleEventDescriptor *)replyEvent
{
NSAppleEventDescriptor *description = [event descriptorAtIndex:1];
NSString *stringValue = description.stringValue;
[IRCExtras parseIRCProtocolURI:stringValue withDescriptor:event];
}
- (void)computerScreenWillSleep:(NSNotification *)note
{
LogToConsole("Preparing for screen sleep");
[self.world prepareForScreenSleep];
}
- (void)computerScreenDidWake:(NSNotification *)note
{
LogToConsole("Waking from screen sleep");
[self.world wakeFromScreenSleep];
}
- (void)computerWillSleep:(NSNotification *)note
{
LogToConsole("Preparing for sleep");
[self.world prepareForSleep];
[[TXSharedApplication sharedSpeechSynthesizer] setIsStopped:YES];
[[TXSharedApplication sharedSpeechSynthesizer] clearQueue];
[[TXSharedApplication sharedNetworkReachabilityNotifier] stopNotifier];
}
- (void)computerDidWakeUp:(NSNotification *)note
{
LogToConsole("Waking from sleep");
[[TXSharedApplication sharedSpeechSynthesizer] setIsStopped:NO];
[[TXSharedApplication sharedNetworkReachabilityNotifier] startNotifier];
[self.world autoConnectAfterWakeup:YES];
}
- (void)computerWillPowerOff:(NSNotification *)note
{
[self terminateGracefully];
}
#pragma mark -
#pragma mark Sparkle Delegate
#if TEXTUAL_BUILT_WITH_SPARKLE_ENABLED == 1
- (void)updaterWillRelaunchApplication:(SPUUpdater *)updater
{
self.applicationIsTerminating = YES;
}
- (NSSet *)allowedChannelsForUpdater:(SPUUpdater *)updater
{
BOOL receiveBetaUpdates = [TPCPreferences receiveBetaUpdates];
if (receiveBetaUpdates) {
return [NSSet setWithObject:@"beta"];
}
return [NSSet set];
}
#endif
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Controllers/TXMenuController.m
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2008 - 2010 Satoshi Nakagawa
* Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "NSObjectHelperPrivate.h"
#import "IRCClientConfig.h"
#import "IRCClientPrivate.h"
#import "IRCChannelPrivate.h"
#import "IRCChannelMode.h"
#import "IRCChannelUser.h"
#import "IRCExtrasPrivate.h"
#import "IRCISupportInfo.h"
#import "IRCUser.h"
#import "IRCWorldPrivate.h"
#import "TVCBasicTableView.h"
#import "TVCLogController.h"
#import "TVCLogViewPrivate.h"
#import "TVCLogViewInternalWK2.h"
#import "TVCMemberList.h"
#import "TVCMainWindowPrivate.h"
#import "TVCMainWindowSplitView.h"
#import "TVCMainWindowTextView.h"
#import "TLOEncryptionManagerPrivate.h"
#import "TLOLicenseManagerPrivate.h"
#import "TLOLocalization.h"
#import "TLOpenLink.h"
#import "TDCAboutDialogPrivate.h"
#import "TDCAlert.h"
#import "TDCChannelInviteSheetPrivate.h"
#import "TDCChannelModifyModesSheetPrivate.h"
#import "TDCChannelModifyTopicSheetPrivate.h"
#import "TDCChannelPropertiesSheetPrivate.h"
#import "TDCChannelSpotlightControllerPrivate.h"
#import "TDCFileTransferDialogPrivate.h"
#import "TDCInputPrompt.h"
#import "TDCLicenseManagerDialogPrivate.h"
#import "TDCNicknameColorSheetPrivate.h"
#import "TDCPreferencesControllerPrivate.h"
#import "TDCServerChangeNicknameSheetPrivate.h"
#import "TDCServerHighlightListSheetPrivate.h"
#import "TDCServerPropertiesSheetPrivate.h"
#import "TDCWelcomeSheetPrivate.h"
#import "TPCPathInfoPrivate.h"
#import "TPCPreferencesImportExport.h"
#import "TPCPreferencesLocalPrivate.h"
#import "TPCPreferencesReload.h"
#import "TPCPreferencesUserDefaults.h"
#import "TXMasterControllerPrivate.h"
#import "TXWindowControllerPrivate.h"
#import "TXMenuControllerPrivate.h"
#if TEXTUAL_BUILT_WITH_SPARKLE_ENABLED == 1
#import
#endif
NS_ASSUME_NONNULL_BEGIN
#define _popWindowViewIfExists(c) if ([windowController() maybeBringWindowForward:(c)]) { \
return; \
}
@interface TXMenuController ()
@property (nonatomic, assign) BOOL menuIsOpen;
@property (nonatomic, assign) BOOL menuPerformedActionLastOpen;
@property (nonatomic, weak) IRCClient *pointedClient;
@property (nonatomic, weak) IRCChannel *pointedChannel;
@property (nonatomic, copy) NSString *currentSearchPhrase;
@property (readonly, nullable) TVCLogController *selectedViewController;
@property (readonly, nullable) TVCLogView *selectedViewControllerBackingView;
@property (readonly) TDCFileTransferDialog *fileTransferController;
@property (nonatomic, strong, readwrite) IBOutlet NSMenu *channelViewChannelNameMenu;
@property (nonatomic, strong, readwrite) IBOutlet NSMenu *channelViewGeneralMenu;
@property (nonatomic, strong, readwrite) IBOutlet NSMenu *channelViewURLMenu;
@property (nonatomic, strong, readwrite) IBOutlet NSMenu *dockMenu;
#if TEXTUAL_BUILT_WITH_ADVANCED_ENCRYPTION == 1
@property (nonatomic, strong, readwrite) IBOutlet NSMenu *encryptionManagerStatusMenu;
#endif
@property (nonatomic, weak, readwrite) IBOutlet NSMenu *mainMenuNavigationChannelListMenu;
@property (nonatomic, weak, readwrite) IBOutlet NSMenu *mainMenuChannelMenu;
@property (nonatomic, weak, readwrite) IBOutlet NSMenu *mainMenuQueryMenu;
@property (nonatomic, weak, readwrite) IBOutlet NSMenuItem *mainMenuChannelMenuItem;
@property (nonatomic, weak, readwrite) IBOutlet NSMenuItem *mainMenuQueryMenuItem;
@property (nonatomic, weak, readwrite) IBOutlet NSMenuItem *mainMenuServerMenuItem;
@property (nonatomic, weak, readwrite) IBOutlet NSMenuItem *mainMenuWindowMenuItem;
@property (nonatomic, strong, readwrite) IBOutlet NSMenu *mainWindowSegmentedControllerCellMenu;
@property (nonatomic, strong, readwrite) IBOutlet NSMenu *serverListNoSelectionMenu;
@property (nonatomic, strong, readwrite) IBOutlet NSMenu *userControlMenu;
@property (nonatomic, weak, readwrite) IBOutlet NSMenuItem *muteNotificationsDockMenuItem;
@property (nonatomic, weak, readwrite) IBOutlet NSMenuItem *muteNotificationsFileMenuItem;
@property (nonatomic, weak, readwrite) IBOutlet NSMenuItem *muteNotificationsSoundsDockMenuItem;
@property (nonatomic, weak, readwrite) IBOutlet NSMenuItem *muteNotificationsSoundsFileMenuItem;
@end
@implementation TXMenuController
- (void)prepareInitialState
{
self.currentSearchPhrase = @"";
if ([TPCPreferences soundIsMuted]) {
self.muteNotificationsSoundsDockMenuItem.state = NSControlStateValueOn;
self.muteNotificationsSoundsFileMenuItem.state = NSControlStateValueOn;
}
[self.channelViewGeneralMenu itemWithTag:MTWKGeneralChannelMenu].submenu = [self.mainMenuChannelMenu copy];
[self setupOtherServices];
[RZNotificationCenter() addObserver:self selector:@selector(menuItemWillPerformedAction:) name:NSMenuWillSendActionNotification object:nil];
[RZNotificationCenter() addObserver:self selector:@selector(menuItemPerformedAction:) name:NSMenuDidSendActionNotification object:nil];
[RZNotificationCenter() addObserver:self selector:@selector(mainWindowSelectionChanged:) name:TVCMainWindowSelectionChangedNotification object:nil];
}
- (void)setupOtherServices
{
[self.fileTransferController startUsingDownloadDestinationURL];
}
- (void)prepareForApplicationTermination
{
LogToConsoleTerminationProgress("Preparing menu controller");
[self.fileTransferController prepareForApplicationTermination];
}
- (void)preferencesChanged
{
[self.fileTransferController clearIPAddress];
}
- (void)mainWindowSelectionChanged:(NSNotification *)notification
{
if (self.menuIsOpen == NO) {
[self resetSelectedItems];
}
/* When the selection changes, menus that may be dynamic are force
revalidated so that Command I (or other shortcuts) work with channel
selected, but not for the server console. */
NSMenuItem *channelMenu = self.mainMenuChannelMenuItem;
[self _forceMenuItemValidation:channelMenu];
NSMenuItem *queryMenu = self.mainMenuQueryMenuItem;
[self _forceMenuItemValidation:queryMenu];
}
- (void)_forceMenuValidation:(NSMenu *)menu
{
NSParameterAssert(menu != nil);
for (NSMenuItem *menuItem in menu.itemArray) {
[self _forceMenuItemValidation:menuItem];
}
}
- (void)_forceMenuItemValidation:(NSMenuItem *)menuItem
{
NSParameterAssert(menuItem != nil);
id target = menuItem.target;
if (target == nil) {
return;
}
if ([target respondsToSelector:@selector(validateMenuItem:)]) {
[target performSelector:@selector(validateMenuItem:) withObject:menuItem];
}
}
- (BOOL)validateMenuItem:(NSMenuItem *)menuItem
{
NSParameterAssert(menuItem != nil);
if (masterController().applicationIsTerminating) {
return NO;
}
/* Menu validation works in two passes:
1. First -_validateMenuItem: is called which performs validation for
the individual menu item including hiding it and related items.
2. The result is then passed to the logic below which performs more
specialized work such as disabling large group of menu items when
the trial has expired.
*/
BOOL validationResult = [self _validateMenuItem:menuItem];
if (validationResult == NO) {
return NO;
}
NSUInteger tag = menuItem.tag;
/* The submenus of the main menu are all targets of the menu
controller so that we can chose to hide or show some depending
on context. For the top most submenus, we have nothing further
to do after performing initial validation. */
switch (tag) {
case MTMainMenuApp:
case MTMainMenuFile:
case MTMainMenuEdit:
case MTMainMenuView:
case MTMainMenuServer:
case MTMainMenuChannel:
case MTMainMenuQuery:
case MTMainMenuNavigate:
case MTMainMenuWindow:
case MTMainMenuHelp:
{
return YES;
}
} // switch
/* When the main window is not the focused window or when we are
in a sheet, most items can be disabled which means at this point
we will default to disabled and allow the bottom logic to enable
only the bare essentials. */
BOOL defaultToNoForSheet = ( mainWindow().attachedSheet != nil ||
(mainWindow().mainWindow == NO &&
mainWindow().isBeneathMouse == NO));
if (defaultToNoForSheet) {
validationResult = NO;
}
/* If the app has not finished launching,
then default everything to disabled. */
if (masterController().applicationIsLaunched == NO) {
validationResult = NO;
}
/* If trial is expired, then default everything to disabled. */
BOOL isTrialExpired = NO;
#if TEXTUAL_BUILT_WITH_LICENSE_MANAGER == 1
if (TLOLicenseManagerTextualIsRegistered() == NO && TLOLicenseManagerIsTrialExpired()) {
/* Set flag letting logic know trial expired */
isTrialExpired = YES;
/* Disable everything by default except "Manage license…" */
validationResult = (tag == MTMMAppManageLicense);
} // if
#endif
/* If certain items are hidden because of sheet but not because
of the trial being expired, then enable additional items. */
if (validationResult == NO && defaultToNoForSheet && isTrialExpired == NO) {
switch (tag) {
case MTMMAppAboutApp: // "About Textual"
case MTMMAppPreferences: // "Preferences…"
case MTMMAppManageLicense: // "Manage license…"
case MTMMAppCheckForUpdates: // "Check for updates…"
case MTMMHelpAdvancedMenuEnableDeveloperMode: // "Enable Developer Mode"
case MTMMHelpAdvancedMenuHiddenPreferences: // "Hidden Preferences…"
case MTMMFileDisableAllNotifications: // "Disable All Notifications"
case MTMMFileDisableAllNotificationSounds: // "Disable All Notification Sounds"
case MTDockMenuDisableAllNotifications: // "Disable All Notifications"
case MTDockMenuDisableAllNotificationSounds: // "Disable All Notification Sounds"
{
validationResult = YES;
break;
}
} // switch
} // if
/* These are the bare minimum of menu items that must be enabled
at all times because they are essential to the entire application. */
/* This list may look incomplete but it isn't. Many menu items,
such as Undo, Cut, Copy, Quit, etc. are not a target of the menu
controller which means they never pass through this logic. */
if (validationResult == NO) {
switch (tag) {
case MTMMAppAboutApp: // "About Textual"
case MTMMAppQuitApp: // "Quit Textual & IRC"
case MTMMFilePrint: // "Print"
case MTMMFileCloseWindow: // "Close Window"
case MTMMEditPaste: // "Paste"
case MTMMViewToggleFullscreen: // "Toggle Fullscreen"
case MTMMWindowMainWindow: // "Main Window"
case MTMMHelpAcknowledgements: // "Acknowledgements"
case MTMMHelpLicenseAgreement: // "License Agreement"
case MTMMHelpPrivacyPolicy: // "Privacy Policy"
case MTMMHelpFrequentlyAskedQuestions: // "Frequently Asked Questions"
case MTMMHelpKnowledgeBaseMenu: // "Knowledge Base"
case MTMMHelpAdvancedMenu: // "Advanced"
case MTMMHelpAdvancedMenuExportPreferences: // "Export Preferences"
{
validationResult = YES;
break;
}
default:
{
if (menuItem.parentItem.tag == MTMMHelpKnowledgeBaseMenu) {
validationResult = YES;
}
break;
}
} // switch
} // if
return validationResult;
}
- (BOOL)_validateMenuItem:(NSMenuItem *)menuItem
{
NSParameterAssert(menuItem != nil);
NSUInteger tag = menuItem.tag;
IRCClient *u = mainWindow().selectedClient;
IRCChannel *c = mainWindow().selectedChannel;
switch (tag) {
case MTMainMenuChannel: // "Channel"
{
BOOL isChannel = c.isChannel;
menuItem.hidden = (isChannel == NO);
if (isChannel) {
menuItem.submenu = self.mainMenuChannelMenu;
} else {
menuItem.submenu = nil;
}
return YES;
}
case MTMainMenuQuery: // "Query"
{
BOOL isQuery = (c.isPrivateMessage || c.isUtility);
menuItem.hidden = (isQuery == NO);
if (isQuery) {
menuItem.submenu = self.mainMenuQueryMenu;
} else {
menuItem.submenu = nil;
}
return YES;
}
case MTMMAppManageLicense: // "Manage license…"
{
#if TEXTUAL_BUILT_WITH_LICENSE_MANAGER == 0
menuItem.hidden = YES;
#endif
return YES;
}
case MTMMAppCheckForUpdates: // "Check for Updates"
{
#if TEXTUAL_BUILT_WITH_SPARKLE_ENABLED == 0
menuItem.hidden = YES;
#endif
return YES;
}
case MTMMFileCloseWindow: // "Close Window"
{
TXCommandWKeyAction keyAction = [TPCPreferences commandWKeyAction];
if (keyAction == TXCommandWKeyActionCloseWindow || mainWindow().keyWindow == NO) {
menuItem.title = TXTLS(@"BasicLanguage[1f6-bg]");
return YES;
}
if (u == nil) {
return NO;
}
switch (keyAction) {
case TXCommandWKeyActionPartChannel:
{
if (c == nil) {
menuItem.title = TXTLS(@"BasicLanguage[1f6-bg]");
return NO;
}
if (c.isChannel) {
menuItem.title = TXTLS(@"BasicLanguage[5td-3f]");
if (c.isActive == NO) {
return NO;
}
} else if (c.isPrivateMessage) {
menuItem.title = TXTLS(@"BasicLanguage[hri-l0]");
} else if (c.isUtility) {
menuItem.title = TXTLS(@"BasicLanguage[hri-l0]");
}
break;
}
case TXCommandWKeyActionDisconnect:
{
menuItem.title = TXTLS(@"BasicLanguage[w3a-je]", u.networkNameAlt);
if (u.isConnecting == NO && u.isConnected == NO) {
return NO;
}
break;
}
case TXCommandWKeyActionTerminate:
{
menuItem.title = TXTLS(@"BasicLanguage[x97-ro]");
break;
}
default:
{
break;
}
}
return YES;
}
case MTMMEditPaste: // "Paste"
case MTWKGeneralPaste: // "Paste" (WebView)
{
NSString *currentPasteboard = RZPasteboard().stringContent;
if (currentPasteboard.length == 0) {
return NO;
}
if (mainWindow().keyWindow) {
return mainWindowTextField().editable;
}
id firstResponder = [NSApp keyWindow].firstResponder;
if ([firstResponder respondsToSelector:@selector(isEditable)]) {
return [firstResponder isEditable];
}
return NO;
}
case MTMMViewMarkScrollback: // "Mark Scrollback"
case MTMMViewScrollbackMarker: // "Scrollback Marker"
case MTMMViewMarkAllAsRead: // "Mark All as Read"
case MTMMViewClearScrollback: // "Clear Scrollback"
case MTMMViewIncreaseFontSize: // "Increase Font Size"
case MTMMViewDecreaseFontSize: // "Decrease Font Size"
case MTMMNavigationJumpToCurrentSession: // "Jump to Current Session"
case MTMMNavigationJumpToPresent: // "Jump to Present"
{
return (self.selectedViewController != nil);
}
case MTMMViewToggleFullscreen:
{
NSWindowCollectionBehavior collectionBehavior = [NSApp keyWindow].collectionBehavior;
return ((collectionBehavior & NSWindowCollectionBehaviorFullScreenAuxiliary) == NSWindowCollectionBehaviorFullScreenAuxiliary ||
(collectionBehavior & NSWindowCollectionBehaviorFullScreenPrimary) == NSWindowCollectionBehaviorFullScreenPrimary);
}
case MTMMServerConnect: // "Connect"
{
if (u == nil) {
menuItem.hidden = NO;
return NO;
}
BOOL connected = (u.isConnected || u.isConnecting);
menuItem.hidden = connected;
return (connected == NO && u.isQuitting == NO);
}
case MTMMServerConnectWithoutProxy: // "Connect Without Proxy"
{
NSUInteger flags = ([NSEvent modifierFlags] & NSEventModifierFlagDeviceIndependentFlagsMask);
if (flags != NSEventModifierFlagShift) {
menuItem.hidden = YES;
return NO;
}
if (u == nil) {
menuItem.hidden = YES;
return NO;
}
BOOL condition = (u.isConnected || u.isConnecting ||
u.config.proxyType == IRCConnectionProxyTypeNone);
menuItem.hidden = condition;
return (condition == NO && u.isQuitting == NO);
}
case MTMMServerDisconnect: // "Disconnect"
{
BOOL connected = (u.isConnected || u.isConnecting);
menuItem.hidden = (connected == NO);
return connected;
}
case MTMMServerCancelReconnect: // "Cancel Reconnect"
{
BOOL reconnecting = u.isReconnecting;
menuItem.hidden = (reconnecting == NO);
return reconnecting;
}
case MTMMServerChannelList: // "Channel List…"
{
return u.isLoggedIn;
}
case MTMMServerChangeNickname: // "Change Nickname…"
case MTWKGeneralChangeNickname: // "Change Nickname…"
{
return u.isConnected;
}
case MTMMServerDuplicateServer: // "Duplicate Server"
case MTMMServerAddChannel: // "Add Channel…"
case MTMMServerServerProperties: // "Server Properties…"
{
return (u != nil);
}
case MTMMServerDeleteServer: // "Delete Server…"
{
return (u && u.isConnecting == NO && u.isConnected == NO);
}
case MTMMNavigationNextHighlight: // "Next Highlight"
case MTMMNavigationPreviousHighlight: // "Previous Highlight"
{
TVCLogController *viewController = self.selectedViewController;
if (viewController == nil) {
return NO;
}
return [viewController highlightAvailable:(tag == MTMMNavigationPreviousHighlight)];
}
case MTMMChannelJoinChannel: // "Join Channel"
{
menuItem.hidden = (u.isLoggedIn == NO || c.isActive);
return YES;
}
case MTMMChannelLeaveChannel: // "Leave Channel"
{
menuItem.hidden = (u.isLoggedIn == NO || c.isActive == NO);
NSMenuItem *joinChannel = [menuItem.menu itemWithTag:MTMMChannelJoinChannel];
[menuItem.menu itemWithTag:MTMMChannelLeaveChannelSeparator].hidden = (menuItem.hidden && joinChannel.hidden);
return YES;
}
case MTMMChannelAddChannel: // "Add Channel…"
{
return (u != nil);
}
case MTMMChannelViewLogs: // "View Logs"
{
return [TPCPreferences logToDiskIsEnabled];
}
case MTMMChannelModifyTopic: // "Modify Topic"
case MTMMChannelModesMenu: // "Modes"
case MTMMChannelListOfBans: // "List of Bans"
{
return (u.isLoggedIn && c.isActive);
}
case MTMMChannelListOfBanExceptions: // "List of Ban Exceptions"
{
menuItem.hidden = ([u.supportInfo isListSupported:IRCISupportInfoListTypeBanException] == NO);
return (u.isLoggedIn && c.isActive);
}
case MTMMChannelListOfInviteExceptions: // "List of Invite Exceptions"
{
menuItem.hidden = ([u.supportInfo isListSupported:IRCISupportInfoListTypeInviteException] == NO);
return (u.isLoggedIn && c.isActive);
}
case MTMMChannelListOfQuiets: // "List of Quiets"
{
menuItem.hidden = ([u.supportInfo isListSupported:IRCISupportInfoListTypeQuiet] == NO);
return (u.isLoggedIn && c.isActive);
}
case MTMMQueryQueryLogs: // "Query Logs"
{
/* Query menu is used for utility windows too so we
hide "Query Logs" for anything except private messages. */
BOOL isQuery = c.isPrivateMessage;
menuItem.hidden = (isQuery == NO);
[menuItem.menu itemWithTag:MTMMQueryCloseQuerySeparator].hidden = (isQuery == NO);
return [TPCPreferences logToDiskIsEnabled];
}
case MTMMWindowToggleVisibilityOfServerList: // "Toggle Visibility of Server List"
case MTMMWindowSortChannelList: // "Sort Channel List"
case MTMMWindowCenterWindow: // "Center Window"
case MTMMWindowResetWindowToDefaultSize: // "Reset Window to Default Size"
{
BOOL isMainWindowMain = mainWindow().mainWindow;
menuItem.hidden = (isMainWindowMain == NO);
if (tag == MTMMWindowSortChannelList) {
[menuItem.menu itemWithTag:MTMMWindowSortChannelListSeparator].hidden = (isMainWindowMain == NO);
} else if (tag == MTMMWindowResetWindowToDefaultSize) {
[menuItem.menu itemWithTag:MTMMWindowResetWindowToDefaultSizeSeparator].hidden = (isMainWindowMain == NO);
}
return YES;
}
case MTMMWindowMainWindow: // "Main Window"
{
BOOL isMainWindowMain = mainWindow().mainWindow;
BOOL isMainWindowDisabled = mainWindow().disabled;
menuItem.hidden = isMainWindowMain;
return (isMainWindowDisabled == NO);
}
case MTMMWindowToggleVisibilityOfMemberList: // "Toggle Visibility of Member List"
{
BOOL isMainWindowMain = mainWindow().mainWindow;
menuItem.hidden = (isMainWindowMain == NO);
return c.isChannel;
}
case MTMMWindowToggleWindowAppearance: // "Toggle Window Appearance"
{
BOOL isMainWindowMain = mainWindow().mainWindow;
menuItem.hidden = (isMainWindowMain == NO);
[menuItem.menu itemWithTag:MTMMWindowToggleWindowAppearanceSeparator].hidden = (isMainWindowMain == NO);
return YES;
}
case MTMMWindowAddressBook: // "Address Book"
case MTMMWindowIgnoreList: // "Ignore List"
{
BOOL isMainWindowMain = mainWindow().mainWindow;
menuItem.hidden = (isMainWindowMain == NO);
return (u != nil);
}
case MTMMWindowViewLogs: // "View Logs"
{
return [TPCPreferences logToDiskIsEnabled];
}
case MTMMWindowHighlightList: // "Highlight List"
{
BOOL isMainWindowMain = mainWindow().mainWindow;
menuItem.hidden = (isMainWindowMain == NO);
if (u == nil) {
return NO;
}
return [TPCPreferences logHighlights];
}
case MTUserControlsAddIgnore: // "Add Ignore"
{
/* To make it as efficient as possible, we only check for ignore
for the "Add Ignore" menu item. When that menu item is validated,
we validate "Modify Ignore" and "Remove Ignore" at the same time. */
NSMenuItem *modifyIgnoreMenuItem = [menuItem.menu itemWithTag:MTUserControlsModifyIgnore];
NSMenuItem *removeIgnoreMenuItem = [menuItem.menu itemWithTag:MTUserControlsRemoveIgnore];
if (c.isUtility) {
modifyIgnoreMenuItem.hidden = YES;
removeIgnoreMenuItem.hidden = YES;
menuItem.hidden = NO;
return NO;
}
/* If less than or more than one user is selected, then hide all
menu items except "Add Ignore" and disable the "Add Ignore" item. */
NSArray *nicknames = [self selectedMembers:menuItem];
NSString *hostmask = nicknames.firstObject.user.hostmask;
if (nicknames.count != 1 || hostmask == nil) {
modifyIgnoreMenuItem.hidden = YES;
removeIgnoreMenuItem.hidden = YES;
menuItem.hidden = NO;
return NO;
}
/* Update visibility depending on whether ignore is available */
/* When this logic was first introduced, we kept a reference to
the ignores in the represented object of the menu item.
This was stopped because information about the ignore can
change while the menu item is still open, making the object
we will reference when action is performed garbage. */
NSArray *userIgnores = [u findIgnoresForHostmask:hostmask];
BOOL condition = (userIgnores.count == 0);
modifyIgnoreMenuItem.hidden = condition;
removeIgnoreMenuItem.hidden = condition;
menuItem.hidden = (condition == NO);
return YES;
}
case MTUserControlsModifyIgnore: // "Modify Ignore"
case MTUserControlsRemoveIgnore: // "Remove Ignore"
{
return YES;
}
case MTUserControlsInviteTo: // "Invite To…"
{
if (u.isLoggedIn == NO || c.isUtility) {
return NO;
}
NSUInteger channelCount = 0;
for (IRCChannel *e in u.channelList) {
if (c != e && e.isChannel) {
channelCount++;
}
}
return (channelCount > 0);
}
case MTUserControlsGetInfo: // "Get Info (Whois)"
case MTUserControlsClientToClientMenu: // "Client-to-Client"
{
return (u.isLoggedIn && c.isUtility == NO);
}
case MTUserControlsPrivateMessage: // "Private Message (Query)"
{
menuItem.hidden = (c.isChannel == NO);
return (u.isLoggedIn && c.isUtility == NO);
}
case MTUserControlsGiveOp: // "Give Op (+o)"
case MTUserControlsGiveHalfop: // "Give Halfop (+h)"
case MTUserControlsGiveVoice: // "Give Voice (+v)"
case MTUserControlsTakeOp: // "Take Op (-o)"
case MTUserControlsTakeHalfop: // "Take Halfop (-h)"
case MTUserControlsTakeVoice: // "Take Voice (-v)"
{
return (u.isLoggedIn && c.isActive);
}
case MTUserControlsAllModesGiven: // "All Modes Given"
{
return NO;
}
case MTUserControlsAllModesTaken: // "All Modes Taken"
{
#define _setHidden(tag, value) [menuItem.menu itemWithTag:(tag)].hidden = (value)
if (c.isChannel == NO) {
_setHidden(MTUserControlsGiveOp, YES);
_setHidden(MTUserControlsGiveHalfop, YES);
_setHidden(MTUserControlsGiveVoice, YES);
_setHidden(MTUserControlsTakeOp, YES);
_setHidden(MTUserControlsTakeHalfop, YES);
_setHidden(MTUserControlsTakeVoice, YES);
_setHidden(MTUserControlsAllModesGiven, YES);
_setHidden(MTUserControlsAllModesGivenSeparator, YES);
_setHidden(MTUserControlsAllModesTaken, YES);
_setHidden(MTUserControlsAllModesTakenSeparator, YES);
return NO;
}
_setHidden(MTUserControlsAllModesGivenSeparator, NO);
_setHidden(MTUserControlsAllModesTakenSeparator, NO);
NSArray *nicknames = [self selectedMembers:menuItem];
if (nicknames.count == 1)
{
IRCChannelUser *user = nicknames[0];
IRCUserRank userRanks = user.ranks;
BOOL UserHasModeO = ((userRanks & IRCUserRankNormalOperator) == IRCUserRankNormalOperator);
BOOL UserHasModeH = NO;
BOOL UserHasModeV = ((userRanks & IRCUserRankVoiced) == IRCUserRankVoiced);
_setHidden(MTUserControlsGiveOp, UserHasModeO);
_setHidden(MTUserControlsGiveVoice, UserHasModeV);
_setHidden(MTUserControlsTakeOp, (UserHasModeO == NO));
_setHidden(MTUserControlsTakeVoice, (UserHasModeV == NO));
BOOL halfOpModeSupported = [u.supportInfo modeSymbolIsUserPrefix:@"h"];
if (halfOpModeSupported == NO) {
_setHidden(MTUserControlsGiveHalfop, YES);
_setHidden(MTUserControlsTakeHalfop, YES);
} else {
UserHasModeH = ((userRanks & IRCUserRankHalfOperator) == IRCUserRankHalfOperator);
_setHidden(MTUserControlsGiveHalfop, UserHasModeH);
_setHidden(MTUserControlsTakeHalfop, (UserHasModeH == NO));
}
BOOL hideGiveSepItem = ((UserHasModeO == NO || UserHasModeV == NO) || (UserHasModeH == NO && halfOpModeSupported));
_setHidden(MTUserControlsAllModesGiven, hideGiveSepItem);
BOOL hideTakenSepItem = (UserHasModeO || UserHasModeH || UserHasModeV);
_setHidden(MTUserControlsAllModesTaken, hideTakenSepItem);
}
else
{
_setHidden(MTUserControlsGiveOp, NO);
_setHidden(MTUserControlsGiveHalfop, NO);
_setHidden(MTUserControlsGiveVoice, NO);
_setHidden(MTUserControlsTakeOp, NO);
_setHidden(MTUserControlsTakeHalfop, NO);
_setHidden(MTUserControlsTakeVoice, NO);
_setHidden(MTUserControlsAllModesGiven, YES);
_setHidden(MTUserControlsAllModesTaken, YES);
}
return NO;
#undef _setHidden
}
case MTUserControlsBan: // "Ban"
case MTUserControlsKick: // "Kick"
case MTUserControlsBanAndKick: // "Ban and Kick"
{
BOOL isChannel = c.isChannel;
menuItem.hidden = (isChannel == NO);
[menuItem.menu itemWithTag:MTUserControlsBanAndKickSeparator].hidden = (isChannel == NO);
return (u.isLoggedIn && isChannel && c.isActive);
}
case MTUserControlsIRCOperatorMenu: // "IRC Operator"
{
menuItem.hidden = (u.userIsIRCop == NO);
return (u.isLoggedIn && c.isUtility == NO);
}
#if TEXTUAL_BUILT_WITH_ADVANCED_ENCRYPTION == 1
case MTOTRStatusButtonStartPrivateConversation:
case MTOTRStatusButtonRefreshPrivateConversation:
case MTOTRStatusButtonEndPrivateConversation:
case MTOTRStatusButtonAuthenticateChatPartner:
case MTOTRStatusButtonViewListOfFingerprints:
{
/* Even if we are not logged in, we still ask the encryption manager
to validate the menu item first so that it can hide specific menu items.
After it has done that, then we can disable if not logged in. */
if ([TPCPreferences textEncryptionIsEnabled] == NO) {
return NO;
}
if (u.isLoggedIn == NO) {
return NO;
}
BOOL valid = [sharedEncryptionManager()
validateMenuItem:menuItem
withStateOf:[u encryptionAccountNameForUser:c.name]
from:[u encryptionAccountNameForLocalUser]];
return valid;
}
#endif
case MTWKGeneralSearchWithGoogle: // "Search With Google"
{
TVCLogView *webView = self.selectedViewControllerBackingView;
if (webView == nil) {
return NO;
}
NSString *searchProviderName = [self searchProviderName];
menuItem.title = TXTLS(@"BasicLanguage[1ll-h9]", searchProviderName);
return webView.hasSelection;
}
case MTWKGeneralLookUpInDictionary: // "Look Up in Dictionary"
{
TVCLogView *webView = self.selectedViewControllerBackingView;
if (webView == nil) {
return NO;
}
NSString *selection = webView.selection;
NSUInteger selectionLength = selection.length;
if (selectionLength == 0 || selectionLength > 40) {
menuItem.title = TXTLS(@"BasicLanguage[o5l-4s]");
return NO;
}
if (selectionLength > 25) {
selection = [selection substringToIndex:24];
selection = [NSString stringWithFormat:@"%@…", selection.trim];
}
menuItem.title = TXTLS(@"BasicLanguage[zxs-yy]", selection);
return (selectionLength > 0);
}
case MTWKGeneralCopy: // "Copy" (WebView)
{
TVCLogView *webView = self.selectedViewControllerBackingView;
if (webView == nil) {
return NO;
}
return webView.hasSelection;
}
case MTWKGeneralQueryLogs: // "Query Logs" (WebKit)
{
menuItem.hidden = (c.isPrivateMessage == NO);
return [TPCPreferences logToDiskIsEnabled];
}
case MTWKGeneralChannelMenu: // "Channel" (WebKit)
{
menuItem.hidden = (c.isChannel == NO);
/* "Query Logs" will appear above this menu item,
but if this is neither channel or query, then we
have to hide the separator above that so it's not
just sitting there with nothing beneath it. */
NSMenuItem *queryLogs = [menuItem.menu itemWithTag:MTWKGeneralQueryLogs];
[menuItem.menu itemWithTag:MTWKGeneralPasteSeparator].hidden = (menuItem.hidden && queryLogs.hidden);
return YES;
}
case MTMMHelpAdvancedMenuEnableDeveloperMode: // Developer Mode
{
if ([TPCPreferences developerModeEnabled]) {
menuItem.state = NSControlStateValueOn;
} else {
menuItem.state = NSControlStateValueOff;
}
return YES;
}
case MTMainWindowSegmentedControllerAddChannel: // "Add Channel…"
{
return (u != nil);
}
default:
{
break;
}
}
return YES;
}
- (void)menuWillOpen:(NSMenu *)menu
{
self.menuIsOpen = YES;
self.pointedClient = mainWindow().selectedClient;
self.pointedChannel = mainWindow().selectedChannel;
self.menuPerformedActionLastOpen = NO;
}
- (void)menuDidClose:(NSMenu *)menu
{
self.menuIsOpen = NO;
/* This delegate callback is received before -menuItemPerformedAction:
is called. So that our selected items can be reset if the user did
not perform an action, we call -menuClosedTimer the next time the
main queue comes around. The action is performed on the current pass
which means this prevents a race. */
XRPerformBlockAsynchronouslyOnMainQueue(^{
[self _menuClosedTimer];
});
}
- (void)_menuClosedTimer
{
if (self.menuPerformedActionLastOpen) {
return;
}
[self resetSelectedItems];
}
- (void)menuItemWillPerformedAction:(NSNotification *)aNote
{
NSMenuItem *menuItem = aNote.userInfo[@"MenuItem"];
if (menuItem.target != self) {
return;
}
self.menuPerformedActionLastOpen = YES;
}
- (void)menuItemPerformedAction:(NSNotification *)aNote
{
NSMenuItem *menuItem = aNote.userInfo[@"MenuItem"];
if (menuItem.target != self) {
return;
}
[self resetSelectedItems];
}
#pragma mark -
#pragma mark Selection
- (void)resetSelectedItems
{
self.pointedClient = nil;
self.pointedChannel = nil;
}
- (nullable IRCClient *)selectedClient
{
IRCClient *pointedClient = self.pointedClient;
if (pointedClient) {
return pointedClient;
}
return mainWindow().selectedClient;
}
- (nullable IRCChannel *)selectedChannel
{
IRCChannel *pointedChannel = self.pointedChannel;
if (pointedChannel) {
return pointedChannel;
}
return mainWindow().selectedChannel;
}
- (nullable TVCLogController *)selectedViewController
{
IRCChannel *selectedChannel = self.selectedChannel;
if (selectedChannel) {
return selectedChannel.viewController;
}
return self.selectedClient.viewController;
}
- (nullable TVCLogView *)selectedViewControllerBackingView
{
TVCLogController *viewController = self.selectedViewController;
return viewController.backingView;
}
#pragma mark -
#pragma mark Selected User(s)
- (BOOL)checkSelectedMembers:(id)sender
{
return ([self selectedMembers:sender].count > 0);
}
- (NSArray *)selectedMembers:(id)sender
{
return [self selectedMembers:sender returnStrings:NO];
}
- (NSArray *)selectedMembersNicknames:(id)sender
{
return [self selectedMembers:sender returnStrings:YES];
}
- (NSArray *)selectedMembers:(id)sender returnStrings:(BOOL)returnStrings
{
IRCClient *u = self.selectedClient;
IRCChannel *c = self.selectedChannel;
if (u == nil || c == nil || u.isLoggedIn == NO || c.isActive == NO) {
return @[];
}
/* Return a specific nickname for WebView events */
NSString *pointedNickname = nil;
if ([sender isKindOfClass:[NSMenuItem class]]) {
pointedNickname = ((NSMenuItem *)sender).userInfo;
} else {
pointedNickname = self.pointedNickname;
}
if (pointedNickname) {
if (returnStrings) {
return @[pointedNickname];
}
IRCChannelUser *user = [c findMember:pointedNickname];
if (user) {
return @[user];
}
return @[];
}
/* If we did not have a specific nickname, then query
the user list for selected rows. */
NSMutableArray *userArray = [NSMutableArray array];
NSIndexSet *selectedRows = mainWindowMemberList().selectedRowIndexes;
[selectedRows enumerateIndexesUsingBlock:^(NSUInteger index, BOOL *stop) {
IRCChannelUser *user = [mainWindowMemberList() itemAtRow:index];
if (returnStrings) {
[userArray addObject:user.user.nickname];
} else {
[userArray addObject:user];
}
}];
return [userArray copy];
}
- (void)deselectMembers:(id)sender
{
if ([sender isKindOfClass:[NSMenuItem class]]) {
if (((NSMenuItem *)sender).userInfo.length > 0) {
return; // Nothing to deselect when our sender used userInfo
}
}
if (self.pointedNickname) {
self.pointedNickname = nil;
return;
}
[mainWindowMemberList() deselectAll:sender];
}
#pragma mark -
#pragma mark Find Panel
- (void)_showFindPromptOpenDialog:(id)sender
{
void (^promptCompletionBlock)(NSString *) = ^(NSString *resultString)
{
if ([self.currentSearchPhrase isEqualToString:resultString]) {
return;
}
self.currentSearchPhrase = resultString;
TVCLogView *webView = self.selectedViewControllerBackingView;
[webView findString:resultString movingForward:YES];
};
NSString *resultString = nil;
TVCAlertResponseButton response =
[TDCInputPrompt promptWithMessage:TXTLS(@"Prompts[d2w-4o]")
title:TXTLS(@"Prompts[akr-eh]")
defaultButton:TXTLS(@"Prompts[q5h-xx]")
alternateButton:TXTLS(@"Prompts[qso-2g]")
prefillString:self.currentSearchPhrase
resultString:&resultString];
if (response == TVCAlertResponseButtonFirst) {
promptCompletionBlock(resultString);
}
}
- (void)showFindPrompt:(id)sender
{
NSParameterAssert(sender != nil);
if (mainWindow().keyWindow == NO) {
return;
}
if ([sender tag] == MTMMEditFindMenuFind || self.currentSearchPhrase.length == 0) {
[self _showFindPromptOpenDialog:sender];
return;
}
TVCLogView *webView = self.selectedViewControllerBackingView;
if ([sender tag] == MTMMEditFindMenuFindNext) {
[webView findString:self.currentSearchPhrase movingForward:YES];
} else {
[webView findString:self.currentSearchPhrase movingForward:NO];
}
}
#pragma mark -
#pragma mark Edit
- (void)copy:(id)sender
{
id firstResponder = [NSApp keyWindow].firstResponder;
if ([firstResponder respondsToSelector:@selector(copy:)]) {
[firstResponder performSelector:@selector(copy:) withObject:sender];
}
}
- (void)paste:(id)sender
{
if (mainWindow().keyWindow) {
[mainWindowTextField() focus];
[mainWindowTextField() paste:sender];
return;
}
id firstResponder = [NSApp keyWindow].firstResponder;
if ([firstResponder respondsToSelector:@selector(paste:)]) {
[firstResponder performSelector:@selector(paste:) withObject:sender];
}
}
- (void)print:(id)sender
{
if (mainWindow().keyWindow) {
TVCLogView *webView = self.selectedViewControllerBackingView;
if (webView == nil) {
return;
}
[webView print];
return;
}
id firstResponder = [NSApp keyWindow].firstResponder;
if ([firstResponder respondsToSelector:@selector(print:)]) {
[firstResponder performSelector:@selector(print:) withObject:sender];
}
}
#pragma mark -
#pragma mark Backing View
- (void)copyLogAsHtml:(id)sender
{
TVCLogView *webView = self.selectedViewControllerBackingView;
if (webView == nil) {
return;
}
[webView copyContentString];
}
- (void)openWebInspector:(id)sender
{
/*
When WebKit2 first announced, there was no way for an
app to take an NSMenu, modify it, and return the result
when a context menu is presented.
WebKit1 had a delegate method for that named:
-webView:contextMenuItemsForElement:defaultMenuItems:
WebKit2 added this delegate method, in private, but it
was not available until the next update of macOS.
'Til then, we had to fake "Inspect Element" because we
did not have access to the default implementation that
is available through the delegate method.
Apple now flags the function names that were used to do that.
This will break "Inspect Element" on one version of macOS.
Which one I don't even recall.
But it is worth it to make the review process smoother.
Sorry.
*/
(void)
[TDCAlert alertWithMessage:TXTLS(@"Prompts[kig-m1]")
title:TXTLS(@"Prompts[ujw-64]")
defaultButton:TXTLS(@"Prompts[c7s-dq]")
alternateButton:nil];
}
- (void)markScrollback:(id)sender
{
TVCLogController *viewController = self.selectedViewController;
if (viewController == nil) {
return;
}
[viewController mark];
}
- (void)gotoScrollbackMarker:(id)sender
{
TVCLogController *viewController = self.selectedViewController;
if (viewController == nil) {
return;
}
[viewController goToMark];
}
- (void)clearScrollback:(id)sender
{
IRCClient *u = self.selectedClient;
IRCChannel *c = self.selectedChannel;
if (u == nil) {
return;
}
if (c) {
[mainWindow() clearContentsOfChannel:c];
} else {
[mainWindow() clearContentsOfClient:u];
}
}
- (void)increaseLogFontSize:(id)sender
{
[mainWindow() changeTextSize:YES];
}
- (void)decreaseLogFontSize:(id)sender
{
[mainWindow() changeTextSize:NO];
}
- (NSString *)searchProviderName
{
NSDictionary *preferredWebServices =
[[NSUserDefaults standardUserDefaults] dictionaryForKey:@"NSPreferredWebServices"];
NSDictionary *defaultSearchProvider = [preferredWebServices dictionaryForKey:@"NSWebServicesProviderWebSearch"];
NSString *searchProviderName = [defaultSearchProvider stringForKey:@"NSDefaultDisplayName"];
if (searchProviderName == nil) {
return @"Google";
}
return searchProviderName;
}
- (void)searchGoogle:(id)sender
{
TVCLogView *webView = self.selectedViewControllerBackingView;
if (webView == nil) {
return;
}
NSString *selection = webView.selection;
if (selection.length == 0) {
return;
}
NSPasteboard *searchPasteboard = [NSPasteboard pasteboardWithUniqueName];
searchPasteboard.stringContent = selection;
NSPerformService(@"Search With %WebSearchProvider@", searchPasteboard);
}
- (void)lookUpInDictionary:(id)sender
{
TVCLogView *webView = self.selectedViewControllerBackingView;
if (webView == nil) {
return;
}
NSString *selection = webView.selection;
if (selection.length == 0) {
return;
}
NSString *urlString = [NSString stringWithFormat:@"dict://%@", selection.percentEncodedString];
[TLOpenLink openWithString:urlString];
}
#pragma mark -
#pragma mark Server
- (void)connect:(id)sender
{
IRCClient *u = self.selectedClient;
if (u == nil || u.isConnecting || u.isConnected || u.isQuitting) {
return;
}
[u connect];
[mainWindow() expandClient:u];
}
- (void)connectBypassingProxy:(id)sender
{
IRCClient *u = self.selectedClient;
if (u == nil || u.isConnecting || u.isConnected || u.isQuitting) {
return;
}
[u connect:IRCClientConnectModeNormal bypassProxy:YES];
[mainWindow() expandClient:u];
}
- (void)disconnect:(id)sender
{
IRCClient *u = self.selectedClient;
if (u == nil || (u.isConnecting == NO && u.isConnected == NO) || u.isQuitting) {
return;
}
[u quit];
}
- (void)cancelReconnection:(id)sender
{
IRCClient *u = self.selectedClient;
if (u == nil) {
return;
}
[u cancelReconnect];
}
- (void)showServerChannelList:(id)sender
{
IRCClient *u = self.selectedClient;
if (u == nil || u.isLoggedIn == NO) {
return;
}
[u createChannelListDialog];
[u requestChannelList];
}
- (void)addServer:(id)sender
{
[windowController() popMainWindowSheetIfExists];
TDCServerPropertiesSheet *sheet =
[[TDCServerPropertiesSheet alloc] initWithClient:nil];
sheet.delegate = self;
sheet.window = mainWindow();
[sheet startWithSelection:TDCServerPropertiesSheetSelectionDefault context:nil];
[windowController() addWindowToWindowList:sheet];
}
- (void)duplicateServer:(id)sender
{
IRCClient *u = self.selectedClient;
if (u == nil) {
return;
}
IRCClientConfigMutable *config = [u.config uniqueCopyMutable];
config.connectionName = [config.connectionName stringByAppendingString:@"_"];
IRCClient *newClient = [worldController() createClientWithConfig:config reload:YES];
if (newClient.config.sidebarItemExpanded) { // Only expand new client if old was expanded already.
[mainWindow() expandClient:newClient];
}
[worldController() save];
}
- (void)deleteServer:(id)sender
{
IRCClient *u = self.selectedClient;
if (u == nil || u.isConnecting || u.isConnected) {
return;
}
BOOL result = [TDCAlert modalAlertWithMessage:TXTLS(@"Prompts[etl-ss]")
title:TXTLS(@"Prompts[0kz-wd]")
defaultButton:TXTLS(@"Prompts[mvh-ms]")
alternateButton:TXTLS(@"Prompts[99q-gg]")];
if (result == NO) {
return;
}
[worldController() destroyClient:u];
[worldController() save];
}
#pragma mark -
#pragma mark Channel
- (void)joinChannel:(id)sender
{
IRCClient *u = self.selectedClient;
IRCChannel *c = self.selectedChannel;
if (u == nil || c == nil || u.isLoggedIn == NO || c.isChannel == NO || c.isActive) {
return;
}
[u joinChannel:c];
[mainWindow() select:c];
}
- (void)leaveChannel:(id)sender
{
IRCClient *u = self.selectedClient;
IRCChannel *c = self.selectedChannel;
/* Second boxed in condition is because this is used for queries too */
if (u == nil || c == nil || (c.isChannel && (u.isLoggedIn == NO || c.isActive == NO))) {
return;
}
if (c.isChannel) {
[u partChannel:c];
return;
}
[worldController() destroyChannel:c];
}
- (void)addChannel:(id)sender
{
[windowController() popMainWindowSheetIfExists];
IRCClient *u = self.selectedClient;
if (u == nil) {
return;
}
TDCChannelPropertiesSheet *sheet =
[[TDCChannelPropertiesSheet alloc] initWithClient:u];
sheet.delegate = self;
sheet.window = mainWindow();
[sheet start];
[windowController() addWindowToWindowList:sheet];
}
- (void)deleteChannel:(id)sender
{
IRCChannel *c = self.selectedChannel;
if (c == nil) {
return;
}
if (c.isChannel) {
BOOL result = [TDCAlert modalAlertWithMessage:TXTLS(@"Prompts[516-ms]")
title:TXTLS(@"Prompts[i8o-7z]")
defaultButton:TXTLS(@"Prompts[mvh-ms]")
alternateButton:TXTLS(@"Prompts[99q-gg]")
suppressionKey:@"delete_channel"
suppressionText:nil];
if (result == NO) {
return;
}
}
[worldController() destroyChannel:c];
[worldController() save];
}
- (void)copyUniqueIdentifier:(id)sender
{
IRCChannel *c = self.selectedChannel;
if (c == nil) {
return;
}
[RZPasteboard() setStringContent:c.uniqueIdentifier];
}
#pragma mark -
#pragma mark Other Actions
- (void)copyUrl:(id)sender
{
NSString *pointedUrl = ((NSMenuItem *)sender).userInfo;
if (pointedUrl.length == 0) {
return;
}
RZPasteboard().stringContent = pointedUrl;
}
- (void)joinChannelClicked:(id)sender
{
NSParameterAssert(sender != nil);
IRCClient *u = self.selectedClient;
if (u == nil || u.isLoggedIn == NO) {
return;
}
NSString *pointedChannelName = nil;
if ([sender isKindOfClass:[NSMenuItem class]]) {
pointedChannelName = ((NSMenuItem *)sender).userInfo;
} else if ([sender isKindOfClass:[NSString class]]) {
pointedChannelName = sender;
} else {
return;
}
if ([u stringIsChannelName:pointedChannelName] == NO) {
return;
}
IRCChannel *c = [u findChannelOrCreate:pointedChannelName];
[u joinChannel:c];
[mainWindow() select:c];
}
- (void)emptyAction:(id)sender
{
/* Empty action used to validate submenus */
}
#pragma mark -
#pragma mark Ignores
- (void)memberAddIgnore:(id)sender
{
IRCClient *u = self.selectedClient;
IRCChannel *c = self.selectedChannel;
if (u == nil || c == nil) {
return;
}
NSArray *nicknames = [self selectedMembersNicknames:sender];
if (nicknames.count == 0) {
return;
}
[self deselectMembers:sender];
NSString *command = [NSString stringWithFormat:@"ignore %@", nicknames[0]];
[u sendCommand:command completeTarget:YES target:c.name];
}
- (void)memberRemoveIgnore:(id)sender
{
IRCClient *u = self.selectedClient;
IRCChannel *c = self.selectedChannel;
if (u == nil || c == nil) {
return;
}
NSArray *nicknames = [self selectedMembersNicknames:sender];
if (nicknames.count == 0) {
return;
}
[self deselectMembers:sender];
NSString *command = [NSString stringWithFormat:@"unignore %@", nicknames[0]];
[u sendCommand:command completeTarget:YES target:c.name];
}
- (void)memberModifyIgnore:(id)sender
{
IRCClient *u = self.selectedClient;
if (u == nil) {
return;
}
NSArray *nicknames = [self selectedMembers:sender];
[self deselectMembers:sender];
/* User's hostmask and other information can change between the point
the menu item is opened and the point the action is performed.
We therefore perform a new query for ignores when performing action. */
NSString *hostmask = nicknames.firstObject.user.hostmask;
if (nicknames.count != 1 || hostmask == nil) {
return;
}
NSArray *userIgnores = [u findIgnoresForHostmask:hostmask];
/* If we have more than one user ignore, then open
the address book instead of a specific ignore. */
if (userIgnores.count == 1) {
[self showServerPropertiesSheetForClient:u
withSelection:TDCServerPropertiesSheetSelectionNewIgnoreEntry
context:userIgnores[0]];
} else {
[self showServerPropertiesSheetForClient:u
withSelection:TDCServerPropertiesSheetSelectionAddressBook
context:nil];
}
}
#pragma mark -
#pragma mark Members
- (void)memberInMemberListDoubleClicked:(id)sender
{
NSInteger rowBeneathMouse = mainWindowMemberList().rowBeneathMouse;
if (rowBeneathMouse < 0) {
return;
}
TXUserDoubleClickAction action = [TPCPreferences userDoubleClickOption];
if (action == TXUserDoubleClickActionWhois) {
[self whoisSelectedMembers:sender];
} else if (action == TXUserDoubleClickActionPrivateMessage) {
[self memberStartPrivateMessage:sender];
} else if (action == TXUserDoubleClickActionInsertTextField) {
[self memberInsertNameIntoTextField:sender];
}
}
- (void)memberInChannelViewDoubleClicked:(id)sender
{
TXUserDoubleClickAction action = [TPCPreferences userDoubleClickOption];
if (action == TXUserDoubleClickActionWhois) {
[self whoisSelectedMembers:sender];
} else if (action == TXUserDoubleClickActionPrivateMessage) {
[self memberStartPrivateMessage:sender];
} else if (action == TXUserDoubleClickActionInsertTextField) {
[self memberInsertNameIntoTextField:sender];
}
}
- (void)memberInsertNameIntoTextField:(id)sender
{
IRCClient *u = self.selectedClient;
IRCChannel *c = self.selectedChannel;
if (u == nil || c == nil) {
return;
}
NSArray *nicknames = [self selectedMembersNicknames:sender];
if (nicknames.count == 0) {
return;
}
[self deselectMembers:sender];
TVCMainWindowTextView *textView = mainWindowTextField();
NSRange selectedRange = textView.selectedRange;
NSMutableString *stringToInsert = [NSMutableString string];
if (selectedRange.location > 0) {
UniChar previousCharacter = [textView.stringValue characterAtIndex:(selectedRange.location - 1)];
if ([[NSCharacterSet whitespaceCharacterSet] characterIsMember:previousCharacter] == NO) {
[stringToInsert appendString:@" "];
}
}
NSString *nicknamesString = [nicknames componentsJoinedByString:@", "];
[stringToInsert appendString:nicknamesString];
NSString *completionSuffix = [TPCPreferences tabCompletionSuffix];
if (completionSuffix != nil) {
[stringToInsert appendString:completionSuffix];
}
[textView replaceCharactersInRange:selectedRange withString:stringToInsert];
[textView resetFontColorInRange:selectedRange];
[textView focus];
}
- (void)memberSendWhois:(id)sender
{
[self whoisSelectedMembers:sender];
}
- (void)whoisSelectedMembers:(id)sender
{
IRCClient *u = self.selectedClient;
IRCChannel *c = self.selectedChannel;
if (u == nil || c == nil) {
return;
}
for (NSString *nickname in [self selectedMembersNicknames:sender]) {
[u sendWhois:nickname];
}
[self deselectMembers:sender];
}
- (void)memberStartPrivateMessage:(id)sender
{
IRCClient *u = self.selectedClient;
IRCChannel *c = self.selectedChannel;
if (u == nil || c == nil) {
return;
}
for (NSString *nickname in [self selectedMembersNicknames:sender]) {
IRCChannel *query = [u findChannelOrCreate:nickname isPrivateMessage:YES];
[mainWindow() select:query];
}
[self deselectMembers:sender];
}
- (void)memberSendCTCPPing:(id)sender
{
IRCClient *u = self.selectedClient;
IRCChannel *c = self.selectedChannel;
if (u == nil || c == nil) {
return;
}
for (NSString *nickname in [self selectedMembersNicknames:sender]) {
[u sendCTCPPing:nickname];
}
[self deselectMembers:sender];
}
- (void)memberSendCTCPFinger:(id)sender
{
IRCClient *u = self.selectedClient;
IRCChannel *c = self.selectedChannel;
if (u == nil || c == nil) {
return;
}
for (NSString *nickname in [self selectedMembersNicknames:sender]) {
[u sendCTCPQuery:nickname command:@"FINGER" text:nil];
}
[self deselectMembers:sender];
}
- (void)memberSendCTCPTime:(id)sender
{
IRCClient *u = self.selectedClient;
IRCChannel *c = self.selectedChannel;
if (u == nil || c == nil) {
return;
}
for (NSString *nickname in [self selectedMembersNicknames:sender]) {
[u sendCTCPQuery:nickname command:@"TIME" text:nil];
}
[self deselectMembers:sender];
}
- (void)memberSendCTCPVersion:(id)sender
{
IRCClient *u = self.selectedClient;
IRCChannel *c = self.selectedChannel;
if (u == nil || c == nil) {
return;
}
for (NSString *nickname in [self selectedMembersNicknames:sender]) {
[u sendCTCPQuery:nickname command:@"VERSION" text:nil];
}
[self deselectMembers:sender];
}
- (void)memberSendCTCPUserinfo:(id)sender
{
IRCClient *u = self.selectedClient;
IRCChannel *c = self.selectedChannel;
if (u == nil || c == nil) {
return;
}
for (NSString *nickname in [self selectedMembersNicknames:sender]) {
[u sendCTCPQuery:nickname command:@"USERINFO" text:nil];
}
[self deselectMembers:sender];
}
- (void)memberSendCTCPClientInfo:(id)sender
{
IRCClient *u = self.selectedClient;
IRCChannel *c = self.selectedChannel;
if (u == nil || c == nil) {
return;
}
for (NSString *nickname in [self selectedMembersNicknames:sender]) {
[u sendCTCPQuery:nickname command:@"CLIENTINFO" text:nil];
}
[self deselectMembers:sender];
}
- (void)_processModeChange:(id)sender usingCommand:(NSString *)modeCommand
{
IRCClient *u = self.selectedClient;
IRCChannel *c = self.selectedChannel;
if (u == nil || c == nil || u.isLoggedIn == NO || c.isChannel == NO) {
return;
}
NSArray *nicknames = [self selectedMembersNicknames:sender];
[self deselectMembers:sender];
NSString *nicknamesString = [nicknames componentsJoinedByString:@" "];
NSString *command = [NSString stringWithFormat:@"%@ %@", modeCommand, nicknamesString];
[u sendCommand:command completeTarget:YES target:c.name];
}
- (void)memberModeGiveOp:(id)sender
{
[self _processModeChange:sender usingCommand:@"OP"];
}
- (void)memberModeTakeOp:(id)sender
{
[self _processModeChange:sender usingCommand:@"DEOP"];
}
- (void)memberModeGiveHalfop:(id)sender
{
[self _processModeChange:sender usingCommand:@"HALFOP"];
}
- (void)memberModeTakeHalfop:(id)sender
{
[self _processModeChange:sender usingCommand:@"DEHALFOP"];
}
- (void)memberModeGiveVoice:(id)sender
{
[self _processModeChange:sender usingCommand:@"VOICE"];
}
- (void)memberModeTakeVoice:(id)sender
{
[self _processModeChange:sender usingCommand:@"DEVOICE"];
}
- (void)memberKickFromChannel:(id)sender
{
IRCClient *u = self.selectedClient;
IRCChannel *c = self.selectedChannel;
if (u == nil || c == nil || u.isLoggedIn == NO || c.isChannel == NO) {
return;
}
for (NSString *nickname in [self selectedMembersNicknames:sender]) {
[u kick:nickname inChannel:c];
}
[self deselectMembers:sender];
}
- (void)memberBanFromChannel:(id)sender
{
IRCClient *u = self.selectedClient;
IRCChannel *c = self.selectedChannel;
if (u == nil || c == nil || u.isLoggedIn == NO || c.isChannel == NO) {
return;
}
for (NSString *nickname in [self selectedMembersNicknames:sender]) {
NSString *command = [NSString stringWithFormat:@"BAN %@", nickname];
[u sendCommand:command completeTarget:YES target:c.name];
}
[self deselectMembers:sender];
}
- (void)memberKickbanFromChannel:(id)sender
{
IRCClient *u = self.selectedClient;
IRCChannel *c = self.selectedChannel;
if (u == nil || c == nil || u.isLoggedIn == NO || c.isChannel == NO) {
return;
}
for (NSString *nickname in [self selectedMembersNicknames:sender]) {
NSString *command = [NSString stringWithFormat:@"KICKBAN %@ %@", nickname, [TPCPreferences defaultKickMessage]];
[u sendCommand:command completeTarget:YES target:c.name];
}
[self deselectMembers:sender];
}
- (void)memberKillFromServer:(id)sender
{
IRCClient *u = self.selectedClient;
IRCChannel *c = self.selectedChannel;
if (u == nil || c == nil || u.isLoggedIn == NO) {
return;
}
for (NSString *nickname in [self selectedMembersNicknames:sender]) {
NSString *command = [NSString stringWithFormat:@"KILL %@ %@", nickname, [TPCPreferences IRCopDefaultKillMessage]];
[u sendCommand:command];
}
[self deselectMembers:sender];
}
- (void)memberBanFromServer:(id)sender
{
IRCClient *u = self.selectedClient;
IRCChannel *c = self.selectedChannel;
if (u == nil || c == nil || u.isLoggedIn == NO) {
return;
}
for (NSString *nickname in [self selectedMembersNicknames:sender]) {
if ([u nicknameIsMyself:nickname]) {
[u printDebugInformation:TXTLS(@"IRC[0r1-5l]", u.serverAddress) inChannel:c];
continue;
}
NSString *command = [NSString stringWithFormat:@"GLINE %@ %@", nickname, [TPCPreferences IRCopDefaultGlineMessage]];
[u sendCommand:command];
}
[self deselectMembers:sender];
}
- (void)memberShunOnServer:(id)sender
{
IRCClient *u = self.selectedClient;
IRCChannel *c = self.selectedChannel;
if (u == nil || c == nil || u.isLoggedIn == NO) {
return;
}
for (NSString *nickname in [self selectedMembersNicknames:sender]) {
NSString *command = [NSString stringWithFormat:@"SHUN %@ %@", nickname, [TPCPreferences IRCopDefaultShunMessage]];
[u sendCommand:command];
}
[self deselectMembers:sender];
}
- (void)_showSetVhostPromptOpenDialog:(id)sender
{
IRCClient *u = self.selectedClient;
IRCChannel *c = self.selectedChannel;
if (u == nil || c == nil || u.isLoggedIn == NO) {
return;
}
NSArray *nicknames = [self selectedMembersNicknames:sender];
if (nicknames.count == 0) {
return;
}
[self deselectMembers:sender];
void (^promptCompletionBlock)(NSString *) = ^(NSString *resultString)
{
NSString *vhost = resultString.trimAndGetFirstToken;
if (vhost.length == 0) {
return;
}
for (NSString *nickname in nicknames) {
NSString *command = [NSString stringWithFormat:@"hs setall %@ %@", nickname, vhost];
[u sendCommand:command completeTarget:NO target:nil];
}
};
NSString *vhost = nil;
TVCAlertResponseButton response =
[TDCInputPrompt promptWithMessage:TXTLS(@"Prompts[2mx-jf]")
title:TXTLS(@"Prompts[7gr-e4]")
defaultButton:TXTLS(@"Prompts[c7s-dq]")
alternateButton:TXTLS(@"Prompts[qso-2g]")
prefillString:nil
resultString:&vhost];
if (response == TVCAlertResponseButtonFirst) {
promptCompletionBlock(vhost);
}
}
- (void)showSetVhostPrompt:(id)sender
{
[self _showSetVhostPromptOpenDialog:sender];
}
#pragma mark -
#pragma mark File Transfers
- (TDCFileTransferDialog *)fileTransferController
{
return [TXSharedApplication sharedFileTransferDialog];
}
- (void)showFileTransfersWindow:(id)sender
{
[self.fileTransferController show:YES restorePosition:YES];
}
- (void)memberSendFileRequest:(id)sender
{
IRCClient *u = self.selectedClient;
IRCChannel *c = self.selectedChannel;
if (u == nil || c == nil || u.isLoggedIn == NO) {
return;
}
NSArray *nicknames = [self selectedMembersNicknames:sender];
if (nicknames.count == 0) {
return;
}
[self deselectMembers:sender];
NSOpenPanel *openPanel = [NSOpenPanel openPanel];
openPanel.allowsMultipleSelection = YES;
openPanel.canChooseDirectories = NO;
openPanel.canChooseFiles = YES;
openPanel.canCreateDirectories = NO;
openPanel.resolvesAliases = YES;
[openPanel beginSheetModalForWindow:mainWindow() completionHandler:^(NSInteger returnCode) {
if (returnCode != NSModalResponseOK) {
return;
}
[self.fileTransferController.fileTransferTable beginUpdates];
for (NSString *nickname in nicknames) {
for (NSURL *path in openPanel.URLs) {
[self.fileTransferController addSenderForClient:u nickname:nickname path:path.path autoOpen:YES];
}
}
[self.fileTransferController.fileTransferTable endUpdates];
}];
}
- (void)memberSendDroppedFilesToSelectedChannel:(NSArray *)files
{
IRCClient *u = self.selectedClient;
IRCChannel *c = self.selectedChannel;
if (u == nil || c == nil || u.isLoggedIn == NO || c.isPrivateMessage == NO) {
return;
}
[self memberSendDroppedFiles:files to:c.name];
}
- (void)memberSendDroppedFiles:(NSArray *)files row:(NSUInteger)row
{
IRCClient *u = self.selectedClient;
IRCChannel *c = self.selectedChannel;
if (u == nil || c == nil || u.isLoggedIn == NO || c.isPrivateMessage == NO) {
return;
}
IRCChannelUser *member = [mainWindowMemberList() itemAtRow:row];
[self memberSendDroppedFiles:files to:member.user.nickname];
}
- (void)memberSendDroppedFiles:(NSArray *)files to:(NSString *)nickname
{
NSParameterAssert(files != nil);
NSParameterAssert(nickname != nil);
IRCClient *u = self.selectedClient;
if (u == nil || u.isLoggedIn == NO) {
return;
}
[self.fileTransferController.fileTransferTable beginUpdates];
for (NSString *file in files) {
BOOL isDirectory = NO;
if ([RZFileManager() fileExistsAtPath:file isDirectory:&isDirectory] == NO) {
continue;
} else if (isDirectory) {
continue;
}
[self.fileTransferController addSenderForClient:u nickname:nickname path:file autoOpen:YES];
}
[self.fileTransferController.fileTransferTable endUpdates];
}
#pragma mark -
#pragma mark Logging
- (void)openLogLocation:(id)sender
{
NSURL *path = [TPCPathInfo transcriptFolderURL];
if (path == nil) {
return;
}
if ([RZFileManager() fileExistsAtURL:path]) {
[RZWorkspace() openURL:path];
return;
}
[TDCAlert modalAlertWithMessage:TXTLS(@"Prompts[f05-hu]")
title:TXTLS(@"Prompts[k55-19]")
defaultButton:TXTLS(@"Prompts[c7s-dq]")
alternateButton:nil];
}
- (void)openChannelLogs:(id)sender
{
IRCClient *u = self.selectedClient;
IRCChannel *c = self.selectedChannel;
if (u == nil || c == nil) {
return;
}
NSURL *path = c.logFilePath;
if (path == nil) {
return;
}
if ([RZFileManager() fileExistsAtURL:path]) {
[RZWorkspace() openURL:path];
return;
}
[TDCAlert modalAlertWithMessage:TXTLS(@"Prompts[f05-hu]")
title:TXTLS(@"Prompts[k55-19]")
defaultButton:TXTLS(@"Prompts[c7s-dq]")
alternateButton:nil];
}
#pragma mark -
#pragma mark Help
- (void)openAcknowledgements:(id)sender
{
NSURL *Acknowledgements = [RZMainBundle() URLForResource:@"Acknowledgements" withExtension:@"pdf" subdirectory:@"Documentation"];
[RZWorkspace() openURL:Acknowledgements];
}
- (void)openHelpMenuItem:(id)sender
{
NSParameterAssert(sender != nil);
NSDictionary *_helpMenuLinks = @{
@(MTMMHelpLicenseAgreement) : @"https://help.codeux.com/textual/End-User-License-Agreement.kb",
@(MTMMHelpPrivacyPolicy) : @"https://help.codeux.com/textual/Privacy-Policy.kb",
@(MTMMHelpFrequentlyAskedQuestions) : @"https://help.codeux.com/textual/Frequently-Asked-Questions.kb",
@(MTMMHelpKBMenuKnowledgeBaseHome) : @"https://help.codeux.com/textual/home.kb",
@(MTMMHelpKBMenuChatEncryption) : @"https://help.codeux.com/textual/Off-the-Record-Messaging.kb",
@(MTMMHelpKBMenuCommandReference) : @"https://help.codeux.com/textual/Command-Reference.kb",
@(MTMMHelpKBMenuFeatureRequests) : @"https://help.codeux.com/textual/Support.kb",
@(MTMMHelpKBMenuKeyboardShortcuts) : @"https://help.codeux.com/textual/Keyboard-Shortcuts.kb",
@(MTMMHelpKBMenuMemoryManagement) : @"https://help.codeux.com/textual/Memory-Management.kb",
@(MTMMHelpKBMenuNetworkTimeouts) : @"https://help.codeux.com/textual/Network-Timeouts.kb",
@(MTMMHelpKBMenuTextFormatting) : @"https://help.codeux.com/textual/Text-Formatting.kb",
@(MTMMHelpKBMenuStylingInformation) : @"https://help.codeux.com/textual/Styles.kb",
@(MTMMHelpKBMenuConnectingWithCertificate) : @"https://help.codeux.com/textual/Using-CertFP.kb",
@(MTMMHelpKBMenuConnectingToBouncer) : @"https://help.codeux.com/textual/Connecting-to-ZNC-Bouncer.kb",
@(MTMMHelpKBMenuDCCFileTransferInformation) : @"https://help.codeux.com/textual/DCC-File-Transfer-Information.kb"
};
NSString *link = _helpMenuLinks[@([sender tag])];
[TLOpenLink openWithString:link inBackground:NO];
}
- (void)openStandaloneStoreWebpage:(id)sender
{
[TLOpenLink openWithString:@"https://www.textualapp.com/standalone-store" inBackground:NO];
}
- (void)contactSupport:(id)sender
{
[TLOpenLink openWithString:@"https://contact.codeux.com/" inBackground:NO];
}
- (void)connectToTextualHelpChannel:(id)sender
{
[IRCExtras createConnectionToServer:@"irc.libera.chat +6697" channelList:@"#textual" connectWhenCreated:YES mergeConnectionIfPossible:YES selectFirstChannelAdded:YES];
}
- (void)connectToTextualTestingChannel:(id)sender
{
[IRCExtras createConnectionToServer:@"irc.libera.chat +6697" channelList:@"#textual-testing" connectWhenCreated:YES mergeConnectionIfPossible:YES selectFirstChannelAdded:YES];
}
#pragma mark -
#pragma mark IRC
- (void)showChannelBanList:(id)sender
{
IRCClient *u = self.selectedClient;
IRCChannel *c = self.selectedChannel;
if (u == nil || c == nil || u.isLoggedIn == NO || c.isChannel == NO) {
return;
}
[u createChannelBanListSheet];
[u sendModes:@"+b" withParameters:nil inChannel:c];
}
- (void)showChannelBanExceptionList:(id)sender
{
IRCClient *u = self.selectedClient;
IRCChannel *c = self.selectedChannel;
if (u == nil || c == nil || u.isLoggedIn == NO || c.isChannel == NO) {
return;
}
[u createChannelBanExceptionListSheet];
[u sendModes:@"+e" withParameters:nil inChannel:c];
}
- (void)showChannelInviteExceptionList:(id)sender
{
IRCClient *u = self.selectedClient;
IRCChannel *c = self.selectedChannel;
if (u == nil || c == nil || u.isLoggedIn == NO || c.isChannel == NO) {
return;
}
[u createChannelInviteExceptionListSheet];
[u sendModes:@"+I" withParameters:nil inChannel:c];
}
- (void)showChannelQuietList:(id)sender
{
IRCClient *u = self.selectedClient;
IRCChannel *c = self.selectedChannel;
if (u == nil || c == nil || u.isLoggedIn == NO || c.isChannel == NO) {
return;
}
[u createChannelQuietListSheet];
[u sendModes:@"+q" withParameters:nil inChannel:c];
}
- (void)toggleChannelModerationMode:(id)sender
{
NSParameterAssert(sender != nil);
IRCClient *u = self.selectedClient;
IRCChannel *c = self.selectedChannel;
if (u == nil || c == nil || u.isLoggedIn == NO || c.isChannel == NO) {
return;
}
NSString *modeSymbol = nil;
if ([sender tag] == MTMMChannelModesMenuRemoveModerated) {
modeSymbol = @"-m";
} else {
modeSymbol = @"+m";
}
[u sendModes:modeSymbol withParameters:nil inChannel:c];
}
- (void)toggleChannelInviteMode:(id)sender
{
NSParameterAssert(sender != nil);
IRCClient *u = self.selectedClient;
IRCChannel *c = self.selectedChannel;
if (u == nil || c == nil || u.isLoggedIn == NO || c.isChannel == NO) {
return;
}
NSString *modeSymbol = nil;
if ([sender tag] == MTMMChannelModesMenuRemoveInviteOnly) {
modeSymbol = @"-i";
} else {
modeSymbol = @"+i";
}
[u sendModes:modeSymbol withParameters:nil inChannel:c];
}
#pragma mark -
#pragma mark Window
- (void)closeWindow:(id)sender
{
TXCommandWKeyAction keyAction = [TPCPreferences commandWKeyAction];
if (keyAction == TXCommandWKeyActionCloseWindow || mainWindow().keyWindow == NO) {
NSWindow *windowToClose = [NSApp keyWindow];
if (windowToClose == nil) {
windowToClose = [NSApp mainWindow];
}
if (windowToClose) {
[windowToClose performClose:sender];
}
return;
}
IRCClient *u = self.selectedClient;
IRCChannel *c = self.selectedChannel;
if (u == nil) {
return;
}
switch (keyAction) {
case TXCommandWKeyActionPartChannel:
{
if (c == nil) {
return;
}
if (c.isChannel) {
if (c.isActive == NO) {
return;
}
[u partChannel:c];
} else {
[worldController() destroyChannel:c];
}
break;
}
case TXCommandWKeyActionDisconnect:
{
if (u.isConnecting == NO && u.isConnected == NO) {
return;
}
[u quit];
break;
}
case TXCommandWKeyActionTerminate:
{
[NSApp terminate:sender];
break;
}
default:
{
break;
}
}
}
- (void)showMainWindow:(id)sender
{
[mainWindow() makeKeyAndOrderFront:sender];
}
- (void)centerMainWindow:(id)sender
{
[mainWindow() exactlyCenterWindow];
}
- (void)toggleFullscreen:(id)sender
{
[[NSApp keyWindow] toggleFullScreen:sender];
}
- (void)resetMainWindowFrame:(id)sender
{
if (mainWindow().inFullscreenMode) {
[mainWindow() toggleFullScreen:sender];
}
[mainWindow() setFrame:[mainWindow() defaultWindowFrame] display:YES animate:YES];
[mainWindow() exactlyCenterWindow];
}
- (void)sortChannelListNames:(id)sender
{
for (IRCClient *u in worldController().clientList) {
NSMutableArray *channelList = [u.channelList mutableCopy];
[channelList sortUsingComparator:^NSComparisonResult(IRCChannel *channel1, IRCChannel *channel2) {
if (channel1.isChannel && channel2.isChannel == NO) {
return NSOrderedAscending;
}
NSString *name1 = channel1.name.lowercaseString;
NSString *name2 = channel2.name.lowercaseString;
return [name1 compare:name2];
}];
if ([channelList isEqualToArray:u.channelList]) {
continue;
}
u.channelList = channelList;
[u reloadServerListItems];
}
[worldController() save];
}
- (void)markAllAsRead:(id)sender
{
[mainWindow() markAllAsRead];
}
#pragma mark -
#pragma mark Preferences
- (void)importPreferences:(id)sender
{
[TPCPreferencesImportExport importInWindow:mainWindow()];
}
- (void)exportPreferences:(id)sender
{
[TPCPreferencesImportExport exportInWindow:mainWindow()];
}
#pragma mark -
#pragma mark Off-the-Record Messaging
#if TEXTUAL_BUILT_WITH_ADVANCED_ENCRYPTION == 1
#define _encryptionNotEnabled ([TPCPreferences textEncryptionIsEnabled] == NO)
- (void)encryptionStartPrivateConversation:(id)sender
{
IRCClient *u = self.selectedClient;
IRCChannel *c = self.selectedChannel;
if (_encryptionNotEnabled || u == nil || c == nil || u.isLoggedIn == NO || c.isPrivateMessage == NO) {
return;
}
[sharedEncryptionManager() beginConversationWith:[u encryptionAccountNameForUser:c.name]
from:[u encryptionAccountNameForLocalUser]];
}
- (void)encryptionRefreshPrivateConversation:(id)sender
{
IRCClient *u = self.selectedClient;
IRCChannel *c = self.selectedChannel;
if (_encryptionNotEnabled || u == nil || c == nil || u.isLoggedIn == NO || c.isPrivateMessage == NO) {
return;
}
[sharedEncryptionManager() refreshConversationWith:[u encryptionAccountNameForUser:c.name]
from:[u encryptionAccountNameForLocalUser]];
}
- (void)encryptionEndPrivateConversation:(id)sender
{
IRCClient *u = self.selectedClient;
IRCChannel *c = self.selectedChannel;
if (_encryptionNotEnabled || u == nil || c == nil || u.isLoggedIn == NO || c.isPrivateMessage == NO) {
return;
}
[sharedEncryptionManager() endConversationWith:[u encryptionAccountNameForUser:c.name]
from:[u encryptionAccountNameForLocalUser]];
}
- (void)encryptionAuthenticateChatPartner:(id)sender
{
IRCClient *u = self.selectedClient;
IRCChannel *c = self.selectedChannel;
if (_encryptionNotEnabled || u == nil || c == nil || u.isLoggedIn == NO || c.isPrivateMessage == NO) {
return;
}
[sharedEncryptionManager() authenticateUser:[u encryptionAccountNameForUser:c.name]
from:[u encryptionAccountNameForLocalUser]];
}
- (void)encryptionListFingerprints:(id)sender
{
[sharedEncryptionManager() presentListOfFingerprints];
}
- (void)encryptionWhatIsThisInformation:(id)sender
{
[TLOpenLink openWithString:@"https://help.codeux.com/textual/Off-the-Record-Messaging.kb" inBackground:NO];
}
#undef _encryptionNotEnabled
#endif
#pragma mark -
#pragma mark Notifications
- (void)toggleMuteOnNotificationsShortcutOn:(BOOL)toggleOn
{
sharedNotificationController().areNotificationsDisabled = toggleOn;
NSControlStateValue state = ((toggleOn) ? NSControlStateValueOn : NSControlStateValueOff);
self.muteNotificationsFileMenuItem.state = state;
self.muteNotificationsDockMenuItem.state = state;
}
- (void)toggleMuteOnNotificationSoundsShortcutOn:(BOOL)toggleOn
{
[TPCPreferences setSoundIsMuted:toggleOn];
NSControlStateValue state = ((toggleOn) ? NSControlStateValueOn : NSControlStateValueOff);
self.muteNotificationsSoundsDockMenuItem.state = state;
self.muteNotificationsSoundsFileMenuItem.state = state;
}
- (void)toggleMuteOnNotificationSounds:(id)sender
{
if ([TPCPreferences soundIsMuted]) {
[self toggleMuteOnNotificationSoundsShortcutOn:NO];
} else {
[self toggleMuteOnNotificationSoundsShortcutOn:YES];
}
}
- (void)toggleMuteOnNotifications:(id)sender
{
if (sharedNotificationController().areNotificationsDisabled) {
[self toggleMuteOnNotificationsShortcutOn:NO];
} else {
[self toggleMuteOnNotificationsShortcutOn:YES];
}
}
#pragma mark -
#pragma mark Appearance
- (void)resetMainWindowAppearance:(id)sender
{
[TPCPreferences setAppearance:TXPreferredAppearanceInherited];
[TPCPreferences performReloadAction:TPCPreferencesReloadActionAppearance];
}
- (void)toggleMainWindowAppearance:(id)sender
{
TXPreferredAppearance appearance = [TPCPreferences appearance];
switch (appearance) {
case TXPreferredAppearanceInherited:
{
TXAppearance *appAppearance = [TXSharedApplication sharedAppearance];
if (appAppearance.properties.isDarkAppearance == NO) {
appearance = TXPreferredAppearanceDark;
} else {
appearance = TXPreferredAppearanceLight;
}
break;
}
case TXPreferredAppearanceLight:
{
appearance = TXPreferredAppearanceDark;
break;
}
case TXPreferredAppearanceDark:
{
appearance = TXPreferredAppearanceLight;
break;
}
} // switch()
[TPCPreferences setAppearance:appearance];
[TPCPreferences performReloadAction:TPCPreferencesReloadActionAppearance];
}
- (void)toggleServerListVisibility:(id)sender
{
[mainWindow().contentSplitView toggleServerListVisibility];
}
- (void)toggleMemberListVisibility:(id)sender
{
mainWindowMemberList().isHiddenByUser = (mainWindowMemberList().isHiddenByUser == NO);
[mainWindow().contentSplitView toggleMemberListVisibility];
}
- (void)forceReloadTheme:(id)sender
{
[mainWindow() reloadTheme];
}
#pragma mark -
#pragma mark License Manager
- (void)manageLicense:(id)sender
{
#if TEXTUAL_BUILT_WITH_LICENSE_MANAGER == 1
[self manageLicense:sender activateLicenseKey:nil licenseKeyPassedByArgument:NO];
#endif
}
#if TEXTUAL_BUILT_WITH_LICENSE_MANAGER == 1
- (void)manageLicense:(id)sender activateLicenseKey:(nullable NSString *)licenseKey
{
[self manageLicense:sender activateLicenseKey:licenseKey licenseKeyPassedByArgument:NO];
}
- (void)manageLicense:(id)sender activateLicenseKeyWithURL:(NSURL *)licenseKeyURL
{
NSParameterAssert(licenseKeyURL != nil);
NSString *path = licenseKeyURL.path;
if (path == nil) {
return;
}
NSCharacterSet *slashCharacterSet = [NSCharacterSet characterSetWithCharactersInString:@"/"];
NSString *licenseKey = [path stringByTrimmingCharactersInSet:slashCharacterSet];
if (licenseKey.length == 0) {
return;
}
[self manageLicense:sender activateLicenseKey:licenseKey licenseKeyPassedByArgument:NO];
}
- (void)manageLicense:(id)sender activateLicenseKey:(nullable NSString *)licenseKey licenseKeyPassedByArgument:(BOOL)licenseKeyPassedByArgument
{
TDCLicenseManagerDialog *licenseDialog = [TXSharedApplication sharedLicenseManagerDialog];
[licenseDialog show];
if (licenseKey) {
[licenseDialog activateLicenseKey:licenseKey silently:licenseKeyPassedByArgument];
}
}
#endif
#pragma mark -
#pragma mark Developer
- (void)toggleDeveloperMode:(id)sender
{
[TPCPreferences setDeveloperModeEnabled:([TPCPreferences developerModeEnabled] == NO)];
[TPCPreferences performReloadAction:TPCPreferencesReloadActionIRCCommandCache];
}
- (void)resetDoNotAskMePopupWarnings:(id)sender
{
NSDictionary *settings = [RZUserDefaults() dictionaryRepresentation];
for (NSString *key in settings) {
if ([key hasPrefix:TDCAlertSuppressionPrefix] == NO) {
continue;
}
[RZUserDefaults() setBool:NO forKey:key];
}
}
#pragma mark -
#pragma mark Sparkle Framework
- (void)checkForUpdates:(id)sender
{
#if TEXTUAL_BUILT_WITH_SPARKLE_ENABLED == 1
SPUStandardUpdaterController *controller = masterController().updateController;
[controller checkForUpdates:sender];
#endif
}
#pragma mark -
#pragma mark Navigation
- (void)navigateToTreeItemAtURL:(NSURL *)url
{
NSParameterAssert(url != nil);
NSString *path = url.path;
if (path == nil) {
return;
}
NSCharacterSet *slashCharacterSet = [NSCharacterSet characterSetWithCharactersInString:@"/"];
NSString *identifier = [path stringByTrimmingCharactersInSet:slashCharacterSet];
if (identifier.length == 0) {
return;
}
[self navigateToTreeItemWithIdentifier:identifier];
}
- (void)navigateToTreeItemWithIdentifier:(NSString *)identifier
{
NSParameterAssert(identifier != nil);
/* Do not use assert for this condition so we
don't crash user when we open a malformed URL. */
if (identifier.length != 36) {
return;
}
IRCTreeItem *item = [worldController() findItemWithId:identifier];
if (item == nil) {
return;
}
[self navigateToTreeItem:item];
}
- (void)navigateToTreeItem:(IRCTreeItem *)item
{
NSParameterAssert(item != nil);
[mainWindow() select:item];
}
- (void)populateNavigationChannelList
{
[self.mainMenuNavigationChannelListMenu removeAllItems];
NSUInteger channelCount = 0;
for (IRCClient *u in worldController().clientList) {
NSMenu *channelSubmenu = [NSMenu new];
NSMenuItem *clientMenuItem = [NSMenuItem new];
clientMenuItem.title = u.name;
clientMenuItem.submenu = channelSubmenu;
for (IRCChannel *c in u.channelList) {
NSMenuItem *channelMenuItem = nil;
if (channelCount >= 10) {
channelMenuItem = [NSMenuItem menuItemWithTitle:c.name
target:self
action:@selector(_navigateToChannelInNavigationList:)];
} else {
NSUInteger keyboardIndex = (channelCount + 1);
if (keyboardIndex == 10) {
keyboardIndex = 0; // Have 0 as the last item.
}
channelMenuItem = [NSMenuItem menuItemWithTitle:c.name
target:self
action:@selector(_navigateToChannelInNavigationList:)
keyEquivalent:[NSString stringWithUniChar:('0' + keyboardIndex)]
keyEquivalentMask:NSEventModifierFlagCommand];
}
channelMenuItem.userInfo = [worldController() pasteboardStringForItem:c];
[channelSubmenu addItem:channelMenuItem];
channelCount += 1;
}
[self.mainMenuNavigationChannelListMenu addItem:clientMenuItem];
}
}
- (void)_navigateToChannelInNavigationList:(NSMenuItem *)sender
{
IRCTreeItem *treeItem = [worldController() findItemWithPasteboardString:sender.userInfo];
if (treeItem == nil) {
return;
}
[mainWindow() select:treeItem];
}
- (void)performNavigationAction:(id)sender
{
NSParameterAssert(sender != nil);
IRCClient *u = self.selectedClient;
if (u == nil) {
return;
}
switch ([sender tag]) {
case MTMMNavigationServersMenuNextServer:
{
[mainWindow() selectNextServer:sender];
break;
}
case MTMMNavigationServersMenuPreviousServer:
{
[mainWindow() selectPreviousServer:sender];
break;
}
case MTMMNavigationServersMenuNextActiveServer:
{
[mainWindow() selectNextActiveServer:sender];
break;
}
case MTMMNavigationServersMenuPreviousActiveServer:
{
[mainWindow() selectPreviousActiveServer:sender];
break;
}
case MTMMNavigationChannelsMenuNextChannel:
{
[mainWindow() selectNextChannel:sender];
break;
}
case MTMMNavigationChannelsMenuPreviousChannel:
{
[mainWindow() selectPreviousChannel:sender];
break;
}
case MTMMNavigationChannelsMenuNextActiveChannel:
{
[mainWindow() selectNextActiveChannel:sender];
break;
}
case MTMMNavigationChannelsMenuPreviousActiveChannel:
{
[mainWindow() selectPreviousActiveChannel:sender];
break;
}
case MTMMNavigationChannelsMenuNextUnreadChannel:
{
[mainWindow() selectNextUnreadChannel:sender];
break;
}
case MTMMNavigationChannelsMenuPreviousUnreadChannel:
{
[mainWindow() selectPreviousUnreadChannel:sender];
break;
}
case MTMMNavigationMoveBackward:
{
[mainWindow() selectPreviousWindow:sender];
break;
}
case MTMMNavigationMoveForward:
{
[mainWindow() selectNextWindow:sender];
break;
}
case MTMMNavigationPreviousSelection:
{
[mainWindow() selectPreviousSelection:sender];
break;
}
} // switch()
}
- (void)onNextHighlight:(id)sender
{
TVCLogController *viewController = self.selectedViewController;
if (viewController == nil) {
return;
}
[viewController nextHighlight];
}
- (void)onPreviousHighlight:(id)sender
{
TVCLogController *viewController = self.selectedViewController;
if (viewController == nil) {
return;
}
[viewController previousHighlight];
}
- (void)jumpToCurrentSession:(id)sender
{
TVCLogController *viewController = self.selectedViewController;
if (viewController == nil) {
return;
}
[viewController jumpToCurrentSession];
}
- (void)jumpToPresent:(id)sender
{
TVCLogController *viewController = self.selectedViewController;
if (viewController == nil) {
return;
}
[viewController jumpToPresent];
}
#pragma mark -
#pragma mark Channel Properties Sheet
- (void)showChannelPropertiesSheet:(id)sender
{
[windowController() popMainWindowSheetIfExists];
IRCClient *u = self.selectedClient;
IRCChannel *c = self.selectedChannel;
if (u == nil || c == nil || c.isChannel == NO) {
return;
}
TDCChannelPropertiesSheet *sheet =
[[TDCChannelPropertiesSheet alloc] initWithChannel:c];
sheet.delegate = self;
sheet.window = mainWindow();
[sheet start];
[windowController() addWindowToWindowList:sheet];
}
- (void)channelPropertiesSheet:(TDCChannelPropertiesSheet *)sender onOk:(IRCChannelConfig *)config
{
IRCClient *u = sender.client;
if (u == nil) {
return;
}
IRCChannel *c = sender.channel;
if (c == nil) {
[worldController() createChannelWithConfig:config onClient:u];
[mainWindow() expandClient:u];
return;
}
[c updateConfig:config];
[worldController() save];
}
- (void)channelPropertiesSheetWillClose:(TDCChannelPropertiesSheet *)sender
{
[windowController() removeWindowFromWindowList:sender];
}
#pragma mark -
#pragma mark Channel Invite Sheet
- (void)memberSendInvite:(id)sender
{
[windowController() popMainWindowSheetIfExists];
IRCClient *u = self.selectedClient;
IRCChannel *c = self.selectedChannel;
if (u == nil || c == nil || u.isLoggedIn == NO || c.isChannel == NO || c.isActive == NO) {
return;
}
NSArray *nicknames = [self selectedMembersNicknames:sender];
if (nicknames.count == 0) {
return;
}
[self deselectMembers:sender];
NSMutableArray *channels = [NSMutableArray array];
for (IRCChannel *e in u.channelList) {
if (c != e && e.isChannel) {
[channels addObject:e.name];
}
}
if (channels.count == 0) {
return;
}
TDCChannelInviteSheet *sheet =
[[TDCChannelInviteSheet alloc] initWithNicknames:nicknames onClient:u];
sheet.delegate = (id)self;
sheet.window = mainWindow();
[sheet startWithChannels:channels];
[windowController() addWindowToWindowList:sheet];
}
- (void)channelInviteSheet:(TDCChannelInviteSheet *)sender onSelectChannel:(NSString *)channelName
{
IRCClient *u = sender.client;
if (u == nil || u.isLoggedIn == NO) {
return;
}
for (NSString *nickname in sender.nicknames) {
[u sendInviteTo:nickname toJoinChannelNamed:channelName];
}
}
- (void)channelInviteSheetWillClose:(TDCChannelInviteSheet *)sender
{
[windowController() removeWindowFromWindowList:sender];
}
#pragma mark -
#pragma mark Address Book Sheet
- (void)showAddressBook:(id)sender
{
IRCClient *u = self.selectedClient;
if (u == nil) {
return;
}
[self showServerPropertiesSheetForClient:u
withSelection:TDCServerPropertiesSheetSelectionAddressBook
context:nil];
}
- (void)showIgnoreList:(id)sender
{
[self showAddressBook:sender];
}
#pragma mark -
#pragma mark Welcome Sheet
- (void)showWelcomeSheet:(id)sender
{
[windowController() popMainWindowSheetIfExists];
TDCWelcomeSheet *sheet =
[[TDCWelcomeSheet alloc] initWithWindow:mainWindow()];
sheet.delegate = (id)self;
[sheet start];
[windowController() addWindowToWindowList:sheet];
}
- (void)welcomeSheet:(TDCWelcomeSheet *)sender onOk:(IRCClientConfig *)config
{
IRCClient *u = [worldController() createClientWithConfig:config reload:YES];
[mainWindow() expandClient:u];
[worldController() save];
[u connect];
[u selectFirstChannelInChannelList];
}
- (void)welcomeSheetWillClose:(TDCWelcomeSheet *)sender
{
[windowController() removeWindowFromWindowList:sender];
}
#pragma mark -
#pragma mark About Window
- (void)showAboutWindow:(id)sender
{
_popWindowViewIfExists(@"TDCAboutDialog");
TDCAboutDialog *dialog = [TDCAboutDialog new];
dialog.delegate = (id)self;
[dialog show];
[windowController() addWindowToWindowList:dialog];
}
- (void)aboutDialogWillClose:(TDCAboutDialog *)sender
{
[windowController() removeWindowFromWindowList:sender];
}
#pragma mark -
#pragma mark Server Properties Sheet
- (void)showServerPropertiesSheetForClient:(IRCClient *)client withSelection:(TDCServerPropertiesSheetSelection)selection context:(nullable id)context
{
NSParameterAssert(client != nil);
[windowController() popMainWindowSheetIfExists];
TDCServerPropertiesSheet *sheet = [[TDCServerPropertiesSheet alloc] initWithClient:client];
sheet.delegate = self;
sheet.window = mainWindow();
[sheet startWithSelection:selection context:context];
[windowController() addWindowToWindowList:sheet];
}
- (void)showServerPropertiesSheet:(id)sender
{
IRCClient *u = self.selectedClient;
if (u == nil) {
return;
}
[self showServerPropertiesSheetForClient:u
withSelection:TDCServerPropertiesSheetSelectionDefault
context:nil];
}
- (void)serverPropertiesSheet:(TDCServerPropertiesSheet *)sender onOk:(IRCClientConfig *)config
{
IRCClient *u = sender.client;
if (u == nil) {
u = [worldController() createClientWithConfig:config reload:YES];
[mainWindow() expandClient:u];
[worldController() save];
return;
}
BOOL sameEncoding = (config.primaryEncoding == u.config.primaryEncoding);
[u updateConfig:config];
if (sameEncoding == NO) {
[mainWindow() reloadTheme];
}
[mainWindow() reloadTreeGroup:u];
[worldController() save];
}
- (void)serverPropertiesSheetWillClose:(TDCServerPropertiesSheet *)sender
{
[windowController() removeWindowFromWindowList:sender];
}
#pragma mark -
#pragma mark Highlight List Sheet
- (void)showServerHighlightList:(id)sender
{
[windowController() popMainWindowSheetIfExists];
IRCClient *u = self.selectedClient;
if (u == nil) {
return;
}
TDCServerHighlightListSheet *sheet =
[[TDCServerHighlightListSheet alloc] initWithClient:u];
sheet.delegate = (id)self;
sheet.window = mainWindow();
[sheet start];
[windowController() addWindowToWindowList:sheet];
}
- (void)serverHighlightListSheetWillClose:(TDCServerHighlightListSheet *)sender
{
[windowController() removeWindowFromWindowList:sender];
}
#pragma mark -
#pragma mark Nickname Color Sheet
- (void)memberChangeColor:(NSString *)nickname
{
NSParameterAssert(nickname != nil);
[windowController() popMainWindowSheetIfExists];
IRCClient *u = self.selectedClient;
if (u == nil) {
return;
}
TDCNicknameColorSheet *sheet =
[[TDCNicknameColorSheet alloc] initWithNickname:nickname];
sheet.delegate = (id)self;
sheet.window = mainWindow();
[sheet start];
[windowController() addWindowToWindowList:sheet];
}
- (void)nicknameColorSheetOnOk:(TDCNicknameColorSheet *)sender
{
[mainWindow() reloadTheme];
}
- (void)nicknameColorSheetWillClose:(TDCNicknameColorSheet *)sender
{
[windowController() removeWindowFromWindowList:sender];
}
#pragma mark -
#pragma mark Channel Topic Sheet
- (void)showChannelModifyTopicSheet:(id)sender
{
[windowController() popMainWindowSheetIfExists];
IRCClient *u = self.selectedClient;
IRCChannel *c = self.selectedChannel;
if (u == nil || c == nil || c.isChannel == NO) {
return;
}
TDCChannelModifyTopicSheet *sheet =
[[TDCChannelModifyTopicSheet alloc] initWithChannel:c];
sheet.delegate = (id)self;
sheet.window = mainWindow();
[sheet start];
[windowController() addWindowToWindowList:sheet];
}
- (void)channelModifyTopicSheet:(TDCChannelModifyTopicSheet *)sender onOk:(NSString *)topic
{
IRCClient *u = sender.client;
IRCChannel *c = sender.channel;
if (u == nil || c == nil || u.isLoggedIn == NO || c.isChannel == NO) {
return;
}
[u sendTopicTo:topic inChannel:c];
}
- (void)channelModifyTopicSheetWillClose:(TDCChannelModifyTopicSheet *)sender
{
[windowController() removeWindowFromWindowList:sender];
}
#pragma mark -
#pragma mark Channel Mode Sheet
- (void)showChannelModifyModesSheet:(id)sender
{
[windowController() popMainWindowSheetIfExists];
IRCClient *u = self.selectedClient;
IRCChannel *c = self.selectedChannel;
if (u == nil || c == nil || c.isChannel == NO) {
return;
}
TDCChannelModifyModesSheet *sheet =
[[TDCChannelModifyModesSheet alloc] initWithChannel:c];
sheet.delegate = (id)self;
sheet.window = mainWindow();
[sheet start];
[windowController() addWindowToWindowList:sheet];
}
- (void)channelModifyModesSheet:(TDCChannelModifyModesSheet *)sender onOk:(IRCChannelModeContainer *)modes
{
IRCClient *u = sender.client;
IRCChannel *c = sender.channel;
if (u == nil || c == nil || u.isLoggedIn == NO || c.isChannel == NO) {
return;
}
NSString *changeString = [c.modeInfo getChangeCommand:modes];
if (changeString.length == 0) {
return;
}
[u sendModes:changeString withParameters:nil inChannel:c];
}
- (void)channelModifyModesSheetWillClose:(TDCChannelModifyModesSheet *)sender
{
[windowController() removeWindowFromWindowList:sender];
}
#pragma mark -
#pragma mark Channel Spotlight Window
- (void)showChannelSpotlightWindow:(id)sender
{
_popWindowViewIfExists(@"TDCChannelSpotlightController");
TDCChannelSpotlightController *dialog = [TDCChannelSpotlightController new];
dialog.delegate = (id)self;
[dialog show];
[windowController() addWindowToWindowList:dialog];
}
- (void)channelSpotlightController:(TDCChannelSpotlightController *)sender selectChannel:(IRCChannel *)channel
{
[mainWindow() select:channel];
}
- (void)channelSpotlightControllerWillClose:(TDCChannelSpotlightController *)sender
{
[windowController() removeWindowFromWindowList:sender];
}
#pragma mark -
#pragma mark Change Nickname Sheet
- (void)showServerChangeNicknameSheet:(id)sender
{
[windowController() popMainWindowSheetIfExists];
IRCClient *u = self.selectedClient;
if (u == nil || u.isLoggedIn == NO) {
return;
}
TDCServerChangeNicknameSheet *sheet =
[[TDCServerChangeNicknameSheet alloc] initWithClient:u];
sheet.delegate = (id)self;
sheet.window = mainWindow();
[sheet start];
[windowController() addWindowToWindowList:sheet];
}
- (void)serverChangeNicknameSheet:(TDCServerChangeNicknameSheet *)sender didInputNickname:(NSString *)nickname
{
IRCClient *u = sender.client;
if (u == nil || u.isConnected == NO) {
return;
}
[u changeNickname:nickname];
}
- (void)serverChangeNicknameSheetWillClose:(TDCServerChangeNicknameSheet *)sender
{
[windowController() removeWindowFromWindowList:sender];
}
#pragma mark -
#pragma mark Preferences Dialog
- (void)showPreferencesWindow:(id)sender
{
[self showPreferencesWindowWithSelection:TDCPreferencesControllerSelectionDefault];
}
- (void)showNotificationPreferences:(id)sender
{
[self showPreferencesWindowWithSelection:TDCPreferencesControllerSelectionNotifications];
}
- (void)showStylePreferences:(id)sender
{
[self showPreferencesWindowWithSelection:TDCPreferencesControllerSelectionStyle];
}
- (void)showHiddenPreferences:(id)sender
{
[self showPreferencesWindowWithSelection:TDCPreferencesControllerSelectionHiddenPreferences];
}
- (void)showPreferencesWindowWithSelection:(TDCPreferencesControllerSelection)selection
{
TDCPreferencesController *openWindow = [windowController() windowFromWindowList:@"TDCPreferencesController"];
if (openWindow) {
[openWindow show:selection];
return;
}
TDCPreferencesController *controller =
[TDCPreferencesController new];
controller.delegate = (id)self;
[controller show:selection];
[windowController() addWindowToWindowList:controller];
}
- (void)preferencesDialogWillClose:(TDCPreferencesController *)sender
{
[TPCPreferences performReloadAction:(TPCPreferencesReloadActionHighlightKeywords |
TPCPreferencesReloadActionPreferencesChanged)];
[windowController() removeWindowFromWindowList:sender];
}
@end
#pragma mark -
#pragma mark Main Window Proxy
@implementation TXMenuControllerMainWindowProxy
- (void)openStandaloneStoreWebpage:(id)sender
{
[menuController() openStandaloneStoreWebpage:sender];
}
- (void)manageLicense:(id)sender
{
[menuController() manageLicense:sender];
}
- (void)showWelcomeSheet:(id)sender
{
[menuController() showWelcomeSheet:sender];
}
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Controllers/TXSharedApplication.m
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "BuildConfig.h"
#import "OELReachability.h"
#import "TXAppearance.h"
#import "TXMasterController.h"
#import "TXMenuController.h"
#import "TXWindowControllerPrivate.h"
#import "TPCThemeController.h"
#import "THOPluginManagerPrivate.h"
#import "IRCWorld.h"
#import "TLOEncryptionManagerPrivate.h"
#import "TLONotificationController.h"
#import "TLOSpeechSynthesizerPrivate.h"
#import "TDCFileTransferDialogPrivate.h"
#import "TDCLicenseManagerDialogPrivate.h"
#import "TVCLogControllerOperationQueuePrivate.h"
#import "TXSharedApplicationPrivate.h"
NS_ASSUME_NONNULL_BEGIN
NSString * const TXErrorDomain = @"TextualErrorDomain";
#define _defineSharedInstance(si_name, si_class, si_init_method) \
+ (si_class *)si_name \
{ \
static id sharedSelf = nil; \
\
static dispatch_once_t onceToken; \
\
dispatch_once(&onceToken, ^{ \
sharedSelf = [si_class si_init_method]; \
}); \
\
return sharedSelf; \
}
@implementation TXSharedApplication
_defineSharedInstance(sharedAppearance, TXAppearance, new)
#if TEXTUAL_BUILT_WITH_ADVANCED_ENCRYPTION == 1
_defineSharedInstance(sharedEncryptionManager, TLOEncryptionManager, new)
#endif
_defineSharedInstance(sharedNetworkReachabilityNotifier, OELReachability, reachabilityForInternetConnection)
_defineSharedInstance(sharedNotificationController, TLONotificationController, new)
_defineSharedInstance(sharedPluginManager, THOPluginManager, new)
_defineSharedInstance(sharedPrintingQueue, TVCLogControllerPrintingOperationQueue, new)
_defineSharedInstance(sharedSpeechSynthesizer, TLOSpeechSynthesizer, new)
_defineSharedInstance(sharedThemeController, TPCThemeController, new)
_defineSharedInstance(sharedWindowController, TXWindowController, new)
#if TEXTUAL_BUILT_WITH_LICENSE_MANAGER == 1
_defineSharedInstance(sharedLicenseManagerDialog, TDCLicenseManagerDialog, new)
#endif
_defineSharedInstance(sharedFileTransferDialog, TDCFileTransferDialog, new)
os_log_t ApplicationTerminationLogSubsystem(void)
{
static os_log_t cachedValue = NULL;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
cachedValue = os_log_create(TXBundleBuildProductIdentifierCString, "Termination");
});
return cachedValue;
}
@end
#pragma mark -
@implementation NSObject (TXSharedApplicationObjectExtension)
__weak static TXMasterController *TXGlobalMasterControllerClassReference;
+ (void)setGlobalMasterControllerClassReference:(id)masterController
{
TXGlobalMasterControllerClassReference = masterController;
}
- (TXMasterController *)masterController
{
return TXGlobalMasterControllerClassReference;
}
+ (TXMasterController *)masterController
{
return TXGlobalMasterControllerClassReference;
}
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Controllers/TXWindowController.m
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "TXMasterController.h"
#import "TVCMainWindow.h"
#import "TXWindowControllerPrivate.h"
NS_ASSUME_NONNULL_BEGIN
@interface TXWindowController ()
@property (nonatomic, strong) NSMutableDictionary *windowObjects;
@end
@implementation TXWindowController
- (instancetype)init
{
if ((self = [super init])) {
[self prepareInitialState];
return self;
}
return nil;
}
- (void)prepareInitialState
{
self.windowObjects = [NSMutableDictionary dictionary];
}
- (void)prepareForApplicationTermination
{
LogToConsoleTerminationProgress("Preparing window controller");
@synchronized(self.windowObjects) {
[self.windowObjects removeAllObjects];
self.windowObjects = nil;
}
}
+ (NSString *)windowDescriptionForWindow:(id)window
{
return [self windowDescriptionForWindow:window inRelationTo:nil];
}
+ (NSString *)windowDescriptionForWindow:(id)window inRelationTo:(nullable id)relatedObject
{
NSParameterAssert(window != nil);
NSString *windowClass = NSStringFromClass([window class]);
if (relatedObject == nil) {
return windowClass;
}
return [NSString stringWithFormat:@"%@ -> %@", windowClass, [relatedObject description]];
}
- (void)addWindowToWindowList:(id)window
{
[self addWindowToWindowList:window inRelationTo:nil];
}
- (void)addWindowToWindowList:(id)window inRelationTo:(nullable id)relatedObject
{
NSString *windowDescription = [self.class windowDescriptionForWindow:window inRelationTo:relatedObject];
[self addWindowToWindowList:window withDescription:windowDescription];
}
- (void)addWindowToWindowList:(id)window withDescription:(NSString *)windowDescription
{
NSParameterAssert(window != nil);
NSAssert([window respondsToSelector:@selector(window)],
@"'window' does not respond to -window");
@synchronized(self.windowObjects) {
self.windowObjects[windowDescription] = window;
}
}
- (void)removeWindowFromWindowList:(id)window
{
[self removeWindowFromWindowList:window inRelationTo:nil];
}
- (void)removeWindowFromWindowList:(id)window inRelationTo:(nullable id)relatedObject
{
NSParameterAssert(window != nil);
if ([window isKindOfClass:[NSArray class]]) {
for (id object in window) {
[self removeWindowFromWindowList:object inRelationTo:relatedObject];
}
return; // Do not continue...
}
BOOL windowWasString = NO;
NSString *windowDescription = nil;
if ([window isKindOfClass:[NSString class]]) {
windowWasString = YES;
windowDescription = window;
} else {
windowDescription = [self.class windowDescriptionForWindow:window inRelationTo:relatedObject];
}
if (windowDescription == nil) {
return; // Cannot continue...
}
@synchronized(self.windowObjects) {
if (self.windowObjects[windowDescription] == nil && windowWasString == NO) {
windowDescription = [self.windowObjects firstKeyForObject:window];
}
if (windowDescription) {
[self.windowObjects removeObjectForKey:windowDescription];
}
}
}
- (nullable id)windowFromWindowList:(NSString *)windowDescription
{
NSParameterAssert(windowDescription != nil);
@synchronized(self.windowObjects) {
return self.windowObjects[windowDescription];
}
}
- (NSArray *)windowsFromWindowList:(NSArray *)windowDescriptions
{
NSParameterAssert(windowDescriptions != nil);
@synchronized(self.windowObjects) {
NSMutableArray *returnedValues = [NSMutableArray array];
for (id windowDescription in windowDescriptions) {
if ([windowDescription isKindOfClass:[NSString class]] == NO) {
continue;
}
id windowObject = self.windowObjects[windowDescription];
if (windowObject) {
[returnedValues addObject:windowObject];
}
}
return [returnedValues copy];
}
}
- (BOOL)maybeBringWindowForward:(NSString *)windowDescription
{
NSParameterAssert(windowDescription != nil);
id windowObject = [self windowFromWindowList:windowDescription];
if (windowObject) {
NSWindow *window = [windowObject window];
[window makeKeyAndOrderFront:nil];
return YES;
}
return NO;
}
- (void)popMainWindowSheetIfExists
{
NSWindow *attachedSheet = mainWindow().attachedSheet;
if (attachedSheet == nil) {
return;
}
[attachedSheet close];
}
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Dialogs/Channel Spotlight/TDCChannelSpotlightAppearance.m
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2018 - 2020Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "NSObjectHelperPrivate.h"
#import "TVCAppearancePrivate.h"
#import "TDCChannelSpotlightControlsPrivate.h"
#import "TDCChannelSpotlightAppearanceInternal.h"
NS_ASSUME_NONNULL_BEGIN
@interface TDCChannelSpotlightAppearance ()
#pragma mark -
#pragma mark Search Field
@property (nonatomic, copy, nullable, readwrite) NSColor *searchFieldTextColor;
@property (nonatomic, copy, nullable, readwrite) NSColor *searchFieldCompletionTextColor;
@property (nonatomic, copy, nullable, readwrite) NSColor *searchFieldNoResultsTextColor;
#pragma mark -
#pragma mark Search Result
@property (nonatomic, copy, nullable, readwrite) NSColor *searchResultRowSelectionColorActiveWindow;
@property (nonatomic, copy, nullable, readwrite) NSColor *searchResultRowSelectionColorInactiveWindow;
@property (nonatomic, assign, readwrite) BOOL searchResultRowEmphasized;
@property (nonatomic, copy, nullable, readwrite) NSColor *searchResultChannelNameTextColor;
@property (nonatomic, copy, nullable, readwrite) NSColor *searchResultChannelDescriptionTextColor;
@property (nonatomic, copy, nullable, readwrite) NSColor *searchResultKeyboardShortcutTextColor;
@property (nonatomic, assign, readwrite) CGFloat searchResultKeyboardShortcutDeselectedOffset;
@property (nonatomic, assign, readwrite) CGFloat searchResultKeyboardShortcutSelectedOffset;
@property (nonatomic, copy, nullable, readwrite) NSColor *searchResultSelectedTextColor;
@end
@implementation TDCChannelSpotlightAppearance
#pragma mark -
#pragma mark Initialization
- (nullable instancetype)initWithWindow:(TDCChannelSpotlightPanel *)window
{
NSParameterAssert(window != nil);
NSURL *appearanceLocation = [self.class appearanceLocation];
BOOL forRetinaDisplay = window.runningInHighResolutionMode;
if ((self = [super initWithAppearanceAtURL:appearanceLocation forRetinaDisplay:forRetinaDisplay])) {
[self prepareInitialState];
return self;
}
return nil;
}
+ (NSURL *)appearanceLocation
{
return [RZMainBundle() URLForResource:@"TDCChannelSpotlightAppearance" withExtension:@"plist"];
}
- (void)prepareInitialState
{
NSDictionary *properties = self.appearanceProperties;
NSDictionary *searchField = properties[@"Search Field"];
self.searchFieldTextColor = [self colorInGroup:searchField withKey:@"controlTextColor"];
self.searchFieldCompletionTextColor = [self colorInGroup:searchField withKey:@"completionTextColor"];
self.searchFieldNoResultsTextColor = [self colorInGroup:searchField withKey:@"noResultsTextColor"];
NSDictionary *searchResult = properties[@"Search Result"];
self.searchResultRowSelectionColorActiveWindow = [self colorInGroup:searchResult withKey:@"selectionColor" forActiveWindow:YES];
self.searchResultRowSelectionColorInactiveWindow = [self colorInGroup:searchResult withKey:@"selectionColor" forActiveWindow:NO];
self.searchResultRowEmphasized = [searchResult boolForKey:@"rowEmphasized"];
self.searchResultChannelNameTextColor = [self colorInGroup:searchResult withKey:@"channelNameTextColor"];
self.searchResultChannelDescriptionTextColor = [self colorInGroup:searchResult withKey:@"channelDescriptionTextColor"];
self.searchResultKeyboardShortcutTextColor = [self colorInGroup:searchResult withKey:@"keyboardShortcutTextColor"];
self.searchResultKeyboardShortcutDeselectedOffset = [self measurementInGroup:searchResult withKey:@"keyboardShortcutDeselectedOffset"];
self.searchResultKeyboardShortcutSelectedOffset = [self measurementInGroup:searchResult withKey:@"keyboardShortcutSelectedOffset"];
self.searchResultSelectedTextColor = [self colorInGroup:searchResult withKey:@"selectedTextColor"];
[self flushAppearanceProperties];
}
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Dialogs/Channel Spotlight/TDCChannelSpotlightController.m
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "NSObjectHelperPrivate.h"
#import "TXMasterController.h"
#import "IRCAddressBookUserTracking.h"
#import "IRCClient.h"
#import "IRCWorld.h"
#import "TPCPreferencesLocal.h"
#import "TPCPreferencesUserDefaults.h"
#import "TLOLicenseManagerPrivate.h"
#import "TLOLocalization.h"
#import "TVCMainWindowPrivate.h"
#import "TDCLicenseManagerDialogPrivate.h"
#import "TDCChannelSpotlightAppearanceInternal.h"
#import "TDCChannelSpotlightSearchResultPrivate.h"
#import "TDCChannelSpotlightSearchResultsTablePrivate.h"
#import "TDCChannelSpotlightControlsPrivate.h"
#import "TDCChannelSpotlightControllerInternal.h"
NS_ASSUME_NONNULL_BEGIN
@interface TDCChannelSpotlightController ()
@property (nonatomic, strong, readwrite) TDCChannelSpotlightAppearance *userInterfaceObjects;
@property (nonatomic, weak) IBOutlet NSVisualEffectView *visualEffectView;
@property (nonatomic, weak) IBOutlet NSTextField *noResultsLabel;
@property (nonatomic, weak) IBOutlet NSLayoutConstraint *noResultsLabelLeadingConstraint;
@property (nonatomic, weak) IBOutlet NSView *searchResultsView;
@property (nonatomic, weak) IBOutlet NSLayoutConstraint *searchResultsViewHeightConstraint;
@property (nonatomic, weak) IBOutlet NSTextField *searchField;
@property (nonatomic, weak) IBOutlet NSTableView *searchResultsTable;
@property (nonatomic, strong) IBOutlet NSArrayController *searchResultsController;
@property (nonatomic, strong) id mouseEventMonitor;
@end
@implementation TDCChannelSpotlightController
#pragma mark -
#pragma mark Initialization
- (instancetype)init
{
if ((self = [super init])) {
[self prepareInitialState];
return self;
}
return nil;
}
- (void)prepareInitialState
{
[RZMainBundle() loadNibNamed:@"TDCChannelSpotlightController" owner:self topLevelObjects:nil];
self.searchResultsTable.doubleAction = @selector(delegatePostSelectChannelForDoubleClickedRow:);
self.mouseEventMonitor =
[NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskKeyDown
handler:^NSEvent *(NSEvent *event) {
return [self respondToKeyDownEvent:event];
}];
self.searchResultsController.sortDescriptors = @[
[NSSortDescriptor sortDescriptorWithKey:@"distance" ascending:NO selector:@selector(compare:)]
];
[RZNotificationCenter() addObserver:self selector:@selector(applicationAppearanceChanged:) name:TXApplicationAppearanceChangedNotification object:nil];
[RZNotificationCenter() addObserver:self selector:@selector(channelListChanged:) name:IRCClientChannelListWasModifiedNotification object:nil];
[RZNotificationCenter() addObserver:self selector:@selector(clientListChanged:) name:IRCWorldClientListWasModifiedNotification object:nil];
[RZNotificationCenter() addObserver:self selector:@selector(mainWindowSelectionChanged:) name:TVCMainWindowSelectionChangedNotification object:nil];
[RZNotificationCenter() addObserver:self selector:@selector(preferencesChanged:) name:TPCPreferencesUserDefaultsDidChangeNotification object:nil];
#if TEXTUAL_BUILT_WITH_LICENSE_MANAGER == 1
[RZNotificationCenter() addObserver:self selector:@selector(licenseManagerDeactivatedLicense:) name:TDCLicenseManagerDeactivatedLicenseNotification object:nil];
[RZNotificationCenter() addObserver:self selector:@selector(licenseManagerTrialExpired:) name:TDCLicenseManagerTrialExpiredNotification object:nil];
#endif
[self populateArrayController];
[self applicationAppearanceChanged];
[self.noResultsLabelLeadingConstraint archiveConstant];
[self.searchResultsViewHeightConstraint archiveConstant];
[self updatePredicate];
}
#pragma mark -
#pragma mark Appearance
- (void)applicationAppearanceChanged:(NSNotification *)notification
{
[self applicationAppearanceChanged];
}
- (void)applicationAppearanceChanged
{
TDCChannelSpotlightAppearance *appearance = [[TDCChannelSpotlightAppearance alloc] initWithWindow:(id)self.window];
self.userInterfaceObjects = appearance;
[self updateVibrancyWithAppearance:appearance];
[self updateControlsWithAppearance:appearance];
[self updateSearchResultsSelection];
}
- (void)updateVibrancyWithAppearance:(TDCChannelSpotlightAppearance *)appearance
{
NSParameterAssert(appearance != nil);
NSAppearance *appKitAppearance = appearance.appKitAppearance;
switch (appearance.appKitAppearanceTarget) {
case TXAppKitAppearanceTargetWindow:
{
self.window.appearance = appKitAppearance;
break;
}
default:
{
break;
}
} // switch()
}
- (void)updateControlsWithAppearance:(TDCChannelSpotlightAppearance *)appearance
{
NSParameterAssert(appearance != nil);
self.searchField.textColor = appearance.searchFieldTextColor;
self.noResultsLabel.textColor = appearance.searchFieldNoResultsTextColor;
}
- (void)updateControlsState
{
NSString *searchString = self.searchField.stringValue;
if (searchString.length == 0) {
self.noResultsLabel.stringValue = @"";
[self.noResultsLabelLeadingConstraint zeroOutConstant];
[self.searchResultsViewHeightConstraint zeroOutConstant];
return;
}
if (self.searchResultsCount == 0) {
self.noResultsLabel.stringValue = TXTLS(@"TDCChannelSpotlightController[tyv-p6]");
[self.noResultsLabelLeadingConstraint restoreArchivedConstant];
[self.searchResultsViewHeightConstraint zeroOutConstant];
return;
}
self.noResultsLabel.stringValue = @"";
[self.noResultsLabelLeadingConstraint zeroOutConstant];
[self.searchResultsViewHeightConstraint restoreArchivedConstant];
[self selectFirstSearchResultIfNecessary];
}
- (void)updateSearchResultsSelection
{
NSTableView *table = self.searchResultsTable;
[table invalidateBackgroundForSelection];
}
#pragma mark -
#pragma mark Events
- (nullable NSEvent *)respondToKeyDownEvent:(NSEvent *)event
{
if (self.window.isKeyWindow == NO) {
return event;
}
switch (event.keyCode) {
case 18 ... 23: // 0-9 (top row)
case 25 ... 26:
case 28 ... 29:
case 82 ... 92: // 0-9 (number pad)
{
NSUInteger keyboardKeys = (event.modifierFlags & NSEventModifierFlagDeviceIndependentFlagsMask);
keyboardKeys &= ~NSEventModifierFlagNumericPad;
if (keyboardKeys == NSEventModifierFlagCommand) {
return [self handleCommandNumberEvent:event];
}
return event;
}
case 36: // return
case 76: // enter
{
[self delegatePostSelectChannelForSelectedRow];
return nil;
}
case 53: // escape
{
[self clearSearchStringOrClose];
return nil;
}
case 126: // arrow up
case 125: // arrow down
case 116: // page up
case 121: // page down
{
return [self handlePageUpDownEvent:event];
}
}
return event;
}
- (nullable NSEvent *)handlePageUpDownEvent:(NSEvent *)event
{
NSUInteger searchResultsCount = self.searchResultsCount;
if (searchResultsCount == 0) {
return nil;
}
NSInteger selectedRow = self.searchResultsTable.selectedRow;
// Wrap around table when we reach the top or bottom
if (event.keyCode == 126 || event.keyCode == 116) { // up
if (selectedRow == 0) {
[self.searchResultsTable selectItemAtIndex:(searchResultsCount - 1)];
return nil;
}
} else if (event.keyCode == 125 || event.keyCode == 121) { // down
if (selectedRow == (searchResultsCount - 1)) {
[self.searchResultsTable selectItemAtIndex:0];
return nil;
}
}
[self.searchResultsTable keyDown:event];
return nil;
}
- (nullable NSEvent *)handleCommandNumberEvent:(NSEvent *)event
{
NSInteger numberPressed = event.characters.integerValue;
if (numberPressed < 0 || numberPressed > 9) {
return event;
}
NSInteger arrayIndex = (numberPressed - 1);
if (arrayIndex < 0) {
arrayIndex = 9;
}
[self delegatePostSelectChannelForSearchResultAtIndex:arrayIndex];
return nil;
}
- (void)delegatePostSelectChannelForDoubleClickedRow:(id)sender
{
NSInteger clickedRow = self.searchResultsTable.clickedRow;
[self delegatePostSelectChannelForSearchResultAtIndex:clickedRow];
}
- (void)delegatePostSelectChannelForSelectedRow
{
NSInteger selectedRow = self.searchResultsTable.selectedRow;
[self delegatePostSelectChannelForSearchResultAtIndex:selectedRow];
}
- (void)delegatePostSelectChannelForSearchResultAtIndex:(NSInteger)searchResultIndex
{
NSArray *searchResults = self.searchResultsFiltered;
if (searchResultIndex < 0 || searchResultIndex >= searchResults.count) {
return;
}
TDCChannelSpotlightSearchResult *searchResult = searchResults[searchResultIndex];
IRCChannel *channel = searchResult.channel;
[self delegatePostSelectChannel:channel];
}
- (void)delegatePostSelectChannel:(IRCChannel *)channel
{
NSParameterAssert(channel != nil);
if ([self.delegate respondsToSelector:@selector(channelSpotlightController:selectChannel:)]) {
[self.delegate channelSpotlightController:self selectChannel:channel];
}
[self close];
}
#pragma mark -
#pragma mark Window Management
- (void)clearSearchStringOrClose
{
/* Mimic Spotlight behavior by clearing search string
on first escape and closing on second escape. */
if (self.searchField.stringValue.length > 0) {
self.searchField.stringValue = @"";
[self searchStringChanged];
return;
}
[self close];
}
- (void)close
{
[self saveWindowFrame];
[self.window close];
}
- (void)show
{
[self restoreWindowFrame];
[self.window makeKeyAndOrderFront:nil];
}
- (void)restoreWindowFrame
{
NSWindow *window = self.window;
[window saveSizeAsDefault];
[window restoreWindowStateForClass:self.class];
}
- (void)saveWindowFrame
{
/* Reset search back to none before closing so
that the frame we save is same we open. */
[self resetSearch];
NSWindow *window = self.window;
/* We call -restoreDefaultSizeAndDisplay: before saving
the frame because the window wont register the changes
to the constants in -resetSearch until next layout pass. */
[window restoreDefaultSizeAndDisplay:NO];
[window saveWindowStateForClass:self.class];
}
#pragma mark -
#pragma mark Search Field
- (NSString *)searchString
{
return self.searchField.stringValue;
}
#pragma mark -
#pragma mark Search Results
- (void)updatePredicate
{
if ([TPCPreferences channelNavigationIsServerSpecific]) {
NSString *clientId = mainWindow().selectedClient.uniqueIdentifier;
self.searchResultsController.filterPredicate = [NSPredicate predicateWithFormat:@"distance >= 0.5 && clientId LIKE[c] %@", clientId];
} else {
self.searchResultsController.filterPredicate = [NSPredicate predicateWithFormat:@"distance >= 0.5"];
}
[self updateControlsState];
}
- (void)resetSearch
{
self.searchField.stringValue = @"";
[self searchStringChanged];
}
- (void)selectFirstSearchResultIfNecessary
{
NSInteger selectedRow = self.searchResultsTable.selectedRow;
if (selectedRow < 0) {
[self.searchResultsTable selectItemAtIndex:0];
}
}
- (NSArray *)searchResults
{
return self.searchResultsController.content;
}
- (NSArray *)searchResultsFiltered
{
return self.searchResultsController.arrangedObjects;
}
- (NSUInteger)searchResultsCount
{
return ((NSArray *)self.searchResultsController.arrangedObjects).count;
}
- (NSInteger)selectedSearchResult
{
return self.searchResultsTable.selectedRow;
}
- (void)recalculateDistanceForSearchResults
{
NSString *searchString = self.searchField.stringValue;
NSArray *searchResults = self.searchResults;
for (TDCChannelSpotlightSearchResult *searchResult in searchResults) {
[searchResult recalculateDistanceWith:searchString];
}
[self updateControlsState];
}
- (void)populateArrayController
{
NSPredicate *filterPredicate = self.searchResultsController.filterPredicate;
self.searchResultsController.filterPredicate = nil;
NSString *searchString = self.searchField.stringValue;
NSMutableArray *searchResults = [NSMutableArray array];
for (IRCClient *client in worldController().clientList) {
for (IRCChannel *channel in client.channelList) {
TDCChannelSpotlightSearchResult *searchResult = [self searchResultForChannel:channel];
[searchResult recalculateDistanceWith:searchString];
[searchResults addObject:searchResult];
}
}
[self.searchResultsController removeAllArrangedObjects];
[self.searchResultsController addObjects:searchResults];
self.searchResultsController.filterPredicate = filterPredicate;
}
- (TDCChannelSpotlightSearchResult *)searchResultForChannel:(IRCChannel *)channel
{
NSParameterAssert(channel != nil);
TDCChannelSpotlightSearchResult *searchResult = [[TDCChannelSpotlightSearchResult alloc] initWithChannel:channel];
return searchResult;
}
- (void)searchStringChanged
{
[self recalculateDistanceForSearchResults];
}
#pragma mark -
#pragma mark Table View Delegate
- (nullable NSTableRowView *)tableView:(NSTableView *)tableView rowViewForRow:(NSInteger)row
{
return [[TDCChannelSpotlightSearchResultRowView alloc] initWithController:self];
}
#pragma mark -
#pragma mark Notifications
- (void)mainWindowSelectionChanged:(NSNotification *)notification
{
/* Predicate is updated when selection changes because predicate may be configured
to be per-server. This could be made more efficient by checking if it is server
specific and comparing the selected client identifier to what is in predicate.
That involves a lot more work for something that shouldn't be fired a lot. */
[self updatePredicate];
}
- (void)preferencesChanged:(NSNotification *)notification
{
NSString *changedKey = notification.userInfo[@"changedKey"];
if ([changedKey isEqualToString:@"ChannelNavigationIsServerSpecific"]) {
[self updatePredicate];
}
}
- (void)clientListChanged:(id)sender
{
[self populateArrayController];
[self updateControlsState];
}
- (void)channelListChanged:(id)sender
{
[self populateArrayController];
[self updateControlsState];
}
- (void)controlTextDidChange:(NSNotification *)notification
{
if (notification.object == self.searchField) {
[self searchStringChanged];
}
}
#if TEXTUAL_BUILT_WITH_LICENSE_MANAGER == 1
- (void)licenseManagerDeactivatedLicense:(NSNotification *)notification
{
if (TLOLicenseManagerIsTrialExpired() == NO) {
return;
}
[self close];
}
- (void)licenseManagerTrialExpired:(NSNotification *)notification
{
[self close];
}
#endif
- (void)windowWillClose:(NSNotification *)notification
{
[NSEvent removeMonitor:self.mouseEventMonitor];
self.mouseEventMonitor = nil;
[RZNotificationCenter() removeObserver:self];
if ([self.delegate respondsToSelector:@selector(channelSpotlightControllerWillClose:)]) {
[self.delegate channelSpotlightControllerWillClose:self];
}
}
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Dialogs/Channel Spotlight/TDCChannelSpotlightControls.m
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "TDCChannelSpotlightControlsPrivate.h"
NS_ASSUME_NONNULL_BEGIN
@implementation TDCChannelSpotlightPanel
- (instancetype)initWithContentRect:(NSRect)contentRect styleMask:(NSWindowStyleMask)style backing:(NSBackingStoreType)bufferingType defer:(BOOL)flag
{
if ((self = [super initWithContentRect:contentRect styleMask:style backing:bufferingType defer:flag])) {
[self prepareInitialState];
}
return self;
}
- (void)prepareInitialState
{
self.styleMask = (self.styleMask | NSWindowStyleMaskFullSizeContentView);
self.titlebarAppearsTransparent = YES;
self.titleVisibility = NSWindowTitleHidden;
[self standardWindowButton:NSWindowCloseButton].hidden = YES;
[self standardWindowButton:NSWindowMiniaturizeButton].hidden = YES;
[self standardWindowButton:NSWindowZoomButton].hidden = YES;
}
- (BOOL)isMovable
{
return YES;
}
- (BOOL)isMovableByWindowBackground
{
return YES;
}
- (BOOL)canBecomeKeyWindow
{
return YES;
}
- (BOOL)canBecomeMainWindow
{
return YES;
}
@end
#pragma mark -
@implementation TDCChannelSpotlightTextField
- (BOOL)mouseDownCanMoveWindow
{
return YES;
}
@end
#pragma mark -
@implementation TDCChannelSpotlightImageView
- (BOOL)mouseDownCanMoveWindow
{
return YES;
}
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Dialogs/Channel Spotlight/TDCChannelSpotlightSearchResult.m
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "NSObjectHelperPrivate.h"
#import "IRCClient.h"
#import "IRCChannel.h"
#import "TDCChannelSpotlightSearchResultPrivate.h"
NS_ASSUME_NONNULL_BEGIN
@interface TDCChannelSpotlightSearchResult ()
@property (nonatomic, weak, readwrite) IRCChannel *channel;
@property (nonatomic, copy, readwrite) NSNumber *distance;
@end
@implementation TDCChannelSpotlightSearchResult
- (instancetype)init
{
[self doesNotRecognizeSelector:_cmd];
return nil;
}
- (instancetype)initWithChannel:(IRCChannel *)channel
{
NSParameterAssert(channel != nil);
if ((self = [super init])) {
self.channel = channel;
[self prepareInitialState];
return self;
}
return nil;
}
- (void)prepareInitialState
{
self.distance = @(0.0);
}
- (NSComparisonResult)compare:(TDCChannelSpotlightSearchResult *)other
{
double localDistance = self.distance.doubleValue;
double remoteDistance = other.distance.doubleValue;
if (localDistance > remoteDistance) {
return NSOrderedAscending;
} else if (localDistance < remoteDistance) {
return NSOrderedDescending;
}
return NSOrderedSame;
}
- (void)recalculateDistanceWith:(NSString *)searchString
{
NSParameterAssert(searchString != nil);
if (searchString.length == 0) {
self.distance = @(0.0);
return;
}
NSString *searchableString = self.channel.name;
double distance = [searchableString compareWithWord:searchString lengthPenaltyWeight:1.0];
self.distance = @(distance);
}
- (NSString *)clientId
{
return self.channel.associatedClient.uniqueIdentifier;
}
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Dialogs/Channel Spotlight/TDCChannelSpotlightSearchResultsTable.m
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "TXGlobalModels.h"
#import "NSViewHelper.h"
#import "TLOLocalization.h"
#import "IRCClient.h"
#import "IRCChannel.h"
#import "TDCChannelSpotlightAppearancePrivate.h"
#import "TDCChannelSpotlightControllerInternal.h"
#import "TDCChannelSpotlightSearchResultPrivate.h"
#import "TDCChannelSpotlightSearchResultsTablePrivate.h"
NS_ASSUME_NONNULL_BEGIN
@interface TDCChannelSpotlightSearchResultRowView ()
@property (nonatomic, weak) TDCChannelSpotlightController *controller;
@property (nonatomic, weak) TDCChannelSpotlightSearchResultCellView *childCell;
@property (readonly) TDCChannelSpotlightAppearance *userInterfaceObjects;
@end
@interface TDCChannelSpotlightSearchResultCellView ()
@property (readonly, copy) NSAttributedString *channelName;
@property (readonly, copy) NSString *keyboardShortcut;
@property (readonly, copy) NSString *unreadCountDescription;
@property (nonatomic, weak) IBOutlet NSTextField *channelNameField;
@property (nonatomic, weak) IBOutlet NSTextField *keyboardShortcutField;
@property (nonatomic, weak) IBOutlet NSLayoutConstraint *keyboardShortcutFieldOffsetConstraint;
@property (nonatomic, weak) IBOutlet NSTextField *unreadCountDescriptionField;
@property (nonatomic, assign) BOOL staticLabelsPopulated;
@property (readonly) TDCChannelSpotlightAppearance *userInterfaceObjects;
@property (readonly) TDCChannelSpotlightController *controller;
@property (readonly) TDCChannelSpotlightSearchResultRowView *rowCell;
@end
@implementation TDCChannelSpotlightSearchResultCellView
- (BOOL)wantsLayer
{
return YES;
}
- (NSViewLayerContentsRedrawPolicy)layerContentsRedrawPolicy
{
return NSViewLayerContentsRedrawOnSetNeedsDisplay;
}
- (void)setInitialValues
{
[self channelNameChanged];
}
- (void)updateLayer
{
[self updateAppearance];
[self keyboardShortcutChanged];
}
- (void)updateAppearance
{
TDCChannelSpotlightSearchResultRowView *rowCell = self.rowCell;
[self updateTextFieldTextColorIsSelected:rowCell.isSelected];
}
- (void)updateTextFieldTextColorIsSelected:(BOOL)isSelected
{
TDCChannelSpotlightAppearance *appearance = self.userInterfaceObjects;
if (isSelected == NO)
{
self.channelNameField.textColor = appearance.searchResultChannelNameTextColor;
self.unreadCountDescriptionField.textColor = appearance.searchResultChannelDescriptionTextColor;
self.keyboardShortcutField.textColor = appearance.searchResultKeyboardShortcutTextColor;
self.keyboardShortcutFieldOffsetConstraint.constant = appearance.searchResultKeyboardShortcutDeselectedOffset;
}
else
{
NSColor *selectedTextColor = appearance.searchResultSelectedTextColor;
self.channelNameField.textColor = selectedTextColor;
self.unreadCountDescriptionField.textColor = selectedTextColor;
self.keyboardShortcutField.textColor = selectedTextColor;
self.keyboardShortcutFieldOffsetConstraint.constant = appearance.searchResultKeyboardShortcutSelectedOffset;
}
}
- (NSAttributedString *)channelName
{
TDCChannelSpotlightSearchResult *searchResult = self.objectValue;
if (searchResult == nil) {
return [NSAttributedString attributedString];
}
static NSMutableParagraphStyle *paragraphStyle = nil;
if (paragraphStyle == nil) {
paragraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
paragraphStyle.lineBreakMode = NSLineBreakByTruncatingTail;
}
NSString *channelName = searchResult.channel.name;
NSFont *channelNameFieldFont = self.channelNameField.font;
NSMutableAttributedString *resultString =
[NSMutableAttributedString
mutableAttributedStringWithString:TXTLS(@"TDCChannelSpotlightController[jpw-cj]", channelName)
attributes:@{
NSFontAttributeName : channelNameFieldFont,
NSParagraphStyleAttributeName : paragraphStyle
}];
TDCChannelSpotlightController *controller = self.controller;
NSString *searchString = controller.searchString;
[resultString.string
enumerateFirstOccurrenceOfCharactersInString:searchString
withBlock:^(NSRange range, BOOL *stop) {
NSFont *boldFont = [RZFontManager() convertFont:channelNameFieldFont toHaveTrait:NSBoldFontMask];
[resultString addAttribute:NSFontAttributeName value:boldFont range:range];
} options:NSCaseInsensitiveSearch];
NSString *networkName = searchResult.channel.associatedClient.networkNameAlt;
[resultString appendString:TXTLS(@"TDCChannelSpotlightController[z68-5q]", networkName)];
return resultString;
}
- (void)channelNameChanged
{
[self willChangeValueForKey:@"channelName"];
[self didChangeValueForKey:@"channelName"];
}
- (NSString *)keyboardShortcut
{
TDCChannelSpotlightSearchResult *searchResult = self.objectValue;
if (searchResult == nil) {
return @"";
}
TDCChannelSpotlightController *controller = self.controller;
NSArray *searchResults = controller.searchResultsFiltered;
NSUInteger searchResultIndex = [searchResults indexOfObjectIdenticalTo:searchResult];
if (searchResultIndex == controller.selectedSearchResult) {
return @"↩︎";
}
if (searchResultIndex > 9) {
return @"";
}
NSUInteger keyboardShortcutIndex = (searchResultIndex + 1);
if (keyboardShortcutIndex == 10) {
keyboardShortcutIndex = 0;
}
return [NSString stringWithFormat:@"⌘%lu", keyboardShortcutIndex];
}
- (void)keyboardShortcutChanged
{
[self willChangeValueForKey:@"keyboardShortcut"];
[self didChangeValueForKey:@"keyboardShortcut"];
}
- (NSString *)unreadCountDescription
{
TDCChannelSpotlightSearchResult *searchResult = self.objectValue;
if (searchResult == nil) {
return @"";
}
NSUInteger nicknameHighlightCount = searchResult.channel.nicknameHighlightCount;
NSString *nicknameHighlightCountDescription = nil;
if (nicknameHighlightCount == 1) {
nicknameHighlightCountDescription = TXTLS(@"TDCChannelSpotlightController[0lz-oh]",TXFormattedNumber(nicknameHighlightCount));
} else {
nicknameHighlightCountDescription = TXTLS(@"TDCChannelSpotlightController[c4u-21]", TXFormattedNumber(nicknameHighlightCount));
}
NSUInteger unreadCount = searchResult.channel.treeUnreadCount;
NSString *unreadCountDescription = nil;
if (unreadCount == 1) {
unreadCountDescription = TXTLS(@"TDCChannelSpotlightController[43s-x4]", TXFormattedNumber(unreadCount));
} else {
unreadCountDescription = TXTLS(@"TDCChannelSpotlightController[vzj-30]", TXFormattedNumber(unreadCount));
}
return TXTLS(@"TDCChannelSpotlightController[et7-c5]", nicknameHighlightCountDescription, unreadCountDescription);
}
- (void)unreadCountDescriptionChanged
{
[self willChangeValueForKey:@"unreadCountDescription"];
[self didChangeValueForKey:@"unreadCountDescription"];
}
- (TDCChannelSpotlightSearchResultRowView *)rowCell
{
return (id)self.superview;
}
- (TDCChannelSpotlightAppearance *)userInterfaceObjects
{
return self.rowCell.userInterfaceObjects;
}
- (TDCChannelSpotlightController *)controller
{
return self.rowCell.controller;
}
- (void)viewDidMoveToWindow
{
[super viewDidMoveToWindow];
TDCChannelSpotlightSearchResult *searchResult = self.objectValue;
IRCChannel *channel = searchResult.channel;
if (self.window == nil)
{
[channel removeObserver:self forKeyPath:@"nicknameHighlightCount"];
[channel removeObserver:self forKeyPath:@"treeUnreadCount"];
}
else
{
[channel addObserver:self forKeyPath:@"nicknameHighlightCount" options:(NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew) context:nil];
[channel addObserver:self forKeyPath:@"treeUnreadCount" options:(NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew) context:nil];
[self setInitialValues];
}
}
- (void)observeValueForKeyPath:(nullable NSString *)keyPath ofObject:(nullable id)object change:(nullable NSDictionary *)change context:(nullable void *)context
{
if ([keyPath isEqualToString:@"nicknameHighlightCount"] ||
[keyPath isEqualToString:@"treeUnreadCount"])
{
[self unreadCountDescriptionChanged];
}
}
@end
#pragma mark -
@implementation TDCChannelSpotlightSearchResultRowView
- (instancetype)initWithController:(TDCChannelSpotlightController *)controller
{
NSParameterAssert(controller != nil);
if ((self = [super initWithFrame:NSZeroRect])) {
self.controller = controller;
return self;
}
return nil;
}
- (void)setSelected:(BOOL)selected
{
super.selected = selected;
if (selected == NO && self.invalidatingBackgroundForSelection) {
return;
}
[self setNeedsDisplayOnChild];
}
- (void)setNeedsDisplayOnChild
{
self.childCell.needsDisplay = YES;
}
- (void)drawSelectionInRect:(NSRect)dirtyRect
{
if ([self needsToDrawRect:dirtyRect] == NO) {
return;
}
BOOL isWindowActive = self.window.isActiveForDrawing;
TDCChannelSpotlightAppearance *appearance = self.userInterfaceObjects;
NSColor *selectionColor = nil;
if (isWindowActive) {
selectionColor = appearance.searchResultRowSelectionColorActiveWindow;
} else {
selectionColor = appearance.searchResultRowSelectionColorInactiveWindow;
} // isWindowActive
if (selectionColor) {
[selectionColor set];
NSRect selectionRect = self.bounds;
NSRectFill(selectionRect);
} else {
[super drawSelectionInRect:dirtyRect];
} // selectionColor
}
- (BOOL)isEmphasized
{
TDCChannelSpotlightAppearance *appearance = self.userInterfaceObjects;
NSWindow *window = self.window;
return (appearance.searchResultRowEmphasized &&
(window == nil || window.isKeyWindow));
}
- (nullable TDCChannelSpotlightSearchResultCellView *)childCell
{
if (self->_childCell == nil) {
if (self.numberOfColumns == 0) {
return nil;
}
self->_childCell = [self viewAtColumn:0];
}
return self->_childCell;
}
- (TDCChannelSpotlightAppearance *)userInterfaceObjects
{
return self.controller.userInterfaceObjects;
}
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Dialogs/File Transfers/TDCFileTransferDialog.m
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2008 - 2010 Satoshi Nakagawa
* Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "NSObjectHelperPrivate.h"
#import "TPCPathInfo.h"
#import "TPCPreferencesLocal.h"
#import "TPCPreferencesUserDefaults.h"
#import "TLOInternetAddressLookup.h"
#import "TLOLocalization.h"
#import "TLOTimer.h"
#import "IRCWorld.h"
#import "TVCBasicTableView.h"
#import "TDCFileTransferDialogTableCellPrivate.h"
#import "TDCFileTransferDialogTransferControllerPrivate.h"
#import "TDCFileTransferDialogInternal.h"
NS_ASSUME_NONNULL_BEGIN
/* Refuse to have more than X number of items incoming at any given time. */
#define _addReceiverHardLimit 120
@interface TDCFileTransferDialog ()
@property (nonatomic, weak) IBOutlet NSButton *clearButton;
@property (nonatomic, weak) IBOutlet NSSegmentedCell *navigationControllerCell;
@property (nonatomic, weak, readwrite) IBOutlet TVCBasicTableView *fileTransferTable;
@property (nonatomic, strong) IBOutlet NSArrayController *fileTransfersController;
@property (nonatomic, strong, nullable) TLOInternetAddressLookup *IPAddressRequest;
@property (readonly) TDCFileTransferDialogSelection navigationSelection;
@property (nonatomic, strong) TLOTimer *maintenanceTimer;
@property (nonatomic, copy, nullable) NSURL *downloadDestinationURLPrivate;
- (IBAction)hideWindow:(id)sender;
- (IBAction)clear:(id)sender;
- (IBAction)startTransferOfFile:(id)sender;
- (IBAction)stopTransferOfFile:(id)sender;
- (IBAction)removeTransferFromList:(id)sender;
- (IBAction)openReceivedFile:(id)sender;
- (IBAction)revealReceivedFileInFinder:(id)sender;
- (IBAction)navigationSelectionDidChange:(id)sender;
@end
@implementation TDCFileTransferDialog
- (instancetype)init
{
if ((self = [super init])) {
[self prepareInitialState];
}
return self;
}
- (void)prepareInitialState
{
[RZMainBundle() loadNibNamed:@"TDCFileTransferDialog" owner:self topLevelObjects:nil];
self.maintenanceTimer =
[TLOTimer timerWithActionBlock:^(TLOTimer *sender) {
[self onMaintenanceTimer];
} onQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)];
[RZNotificationCenter() addObserver:self selector:@selector(clientWillBeDestroyed:) name:IRCWorldWillDestroyClientNotification object:nil];
}
- (void)dealloc
{
[RZNotificationCenter() removeObserver:self];
[self.maintenanceTimer stop];
self.maintenanceTimer = nil;
}
- (void)show
{
[self show:YES restorePosition:YES];
}
- (void)show:(BOOL)makeKeyWindow
{
[self show:makeKeyWindow restorePosition:YES];
}
- (void)show:(BOOL)makeKeyWindow restorePosition:(BOOL)restorePosition
{
if (makeKeyWindow) {
[self.window makeKeyAndOrderFront:nil];
} else {
[self.window orderFront:nil];
}
if (restorePosition) {
[self.window restoreWindowStateForClass:self.class];
}
}
- (nullable TDCFileTransferDialogTransferController *)fileTransferMatchingPort:(uint16_t)port
{
TDCFileTransferDialogTransferController *fileTransfer =
[self fileTransferMatchingCondition:^BOOL(TDCFileTransferDialogTransferController *controller) {
return (controller.hostPort == port);
}];
return fileTransfer;
}
- (nullable TDCFileTransferDialogTransferController *)fileTransferWithUniqueIdentifier:(NSString *)identifier
{
NSParameterAssert(identifier != nil);
TDCFileTransferDialogTransferController *fileTransfer =
[self fileTransferMatchingCondition:^BOOL(TDCFileTransferDialogTransferController *controller) {
return [identifier isEqualToString:controller.uniqueIdentifier];
}];
return fileTransfer;
}
- (BOOL)fileTransferExistsWithToken:(NSString *)transferToken
{
NSParameterAssert(transferToken != nil);
TDCFileTransferDialogTransferController *fileTransfer =
[self fileTransferMatchingCondition:^BOOL(TDCFileTransferDialogTransferController *controller) {
return [transferToken isEqualToString:controller.transferToken];
}];
return (fileTransfer != nil);
}
- (nullable TDCFileTransferDialogTransferController *)fileTransferSenderMatchingToken:(NSString *)transferToken
{
NSParameterAssert(transferToken != nil);
TDCFileTransferDialogTransferController *fileTransfer =
[self fileTransferMatchingCondition:^BOOL(TDCFileTransferDialogTransferController *controller) {
return ([transferToken isEqualToString:controller.transferToken] && controller.isSender);
}];
return fileTransfer;
}
- (nullable TDCFileTransferDialogTransferController *)fileTransferReceiverMatchingToken:(NSString *)transferToken
{
NSParameterAssert(transferToken != nil);
TDCFileTransferDialogTransferController *fileTransfer =
[self fileTransferMatchingCondition:^BOOL(TDCFileTransferDialogTransferController *controller) {
return ([transferToken isEqualToString:controller.transferToken] && controller.isSender == NO);
}];
return fileTransfer;
}
- (void)prepareForApplicationTermination
{
LogToConsoleTerminationProgress("Stopping access to download destination bookmark");
if (self.downloadDestinationURLPrivate) {
[self.downloadDestinationURLPrivate stopAccessingSecurityScopedResource];
}
LogToConsoleTerminationProgress("Closing file transfer window");
[self close];
LogToConsoleTerminationProgress("Preparing all file transfers for destruction");
[self enumerateFileTransfers:^(TDCFileTransferDialogTransferController *fileTransfer, BOOL *stop) {
[fileTransfer prepareForPermanentDestruction];
}];
}
- (nullable NSString *)addReceiverForClient:(IRCClient *)client nickname:(NSString *)nickname address:(NSString *)hostAddress port:(uint16_t)hostPort filename:(NSString *)filename filesize:(uint64_t)totalFilesize token:(nullable NSString *)transferToken
{
NSParameterAssert(client != nil);
NSParameterAssert(nickname != nil);
NSParameterAssert(hostAddress != nil);
NSParameterAssert(filename != nil);
/* A hard limit exists to prevent a bad person continuously sending file transfers
which appear in the file transfer, exhausting resources. */
if ([self receiverCount] > _addReceiverHardLimit) {
LogToConsoleError("Max receiver count of %{public}i exceeded", _addReceiverHardLimit);
return nil;
}
TDCFileTransferDialogTransferController *controller = [TDCFileTransferDialogTransferController receiverForClient:client nickname:nickname address:hostAddress port:hostPort filename:filename filesize:totalFilesize token:transferToken];
if (controller == nil) {
return nil;
}
[self show:NO restorePosition:NO];
[self addFileTransfer:controller];
NSString *savePath = self.downloadDestinationURLPrivate.path;
if ([TPCPreferences fileTransferRequestReplyAction] == TXFileTransferRequestReplyAutomaticallyDownload) {
if (savePath == nil) {
savePath = [TPCPathInfo userDownloads];
}
[controller openWithPath:savePath];
}
return controller.uniqueIdentifier;
}
- (nullable NSString *)addSenderForClient:(IRCClient *)client nickname:(NSString *)nickname path:(NSString *)path autoOpen:(BOOL)autoOpen
{
NSParameterAssert(client != nil);
NSParameterAssert(nickname != nil);
NSParameterAssert(path != nil);
TDCFileTransferDialogTransferController *controller = [TDCFileTransferDialogTransferController senderForClient:client nickname:nickname path:path];
if (controller == nil) {
return nil;
}
[self show:YES restorePosition:NO];
[self addFileTransfer:controller];
if (autoOpen) {
[controller open];
}
return controller.uniqueIdentifier;
}
- (void)updateClearButton
{
NSArray *stoppedFileTransfers = [self stoppedFileTransfers];
self.clearButton.enabled = (stoppedFileTransfers.count > 0);
}
- (void)addFileTransfer:(TDCFileTransferDialogTransferController *)controller
{
/* Resetting the predicate the each time a controller is added is stupid,
but this is a low frequency task that we can forgive. */
NSPredicate *filterPredicate = self.fileTransfersController.filterPredicate;
self.fileTransfersController.filterPredicate = nil;
[self.fileTransfersController insertObject:controller atArrangedObjectIndex:0];
self.fileTransfersController.filterPredicate = filterPredicate;
}
- (void)removeFileTransfersMatchingClient:(IRCClient *)client
{
NSParameterAssert(client != nil);
NSArray *fileTransfers = [self fileTransfersMatchingClient:client];
if (fileTransfers.count == 0) {
return;
}
[fileTransfers makeObjectsPerformSelector:@selector(prepareForPermanentDestruction)];
[self.fileTransfersController removeObjects:fileTransfers];
}
#pragma mark -
#pragma mark Notifications
- (void)clientWillBeDestroyed:(NSNotification *)notification
{
[self removeFileTransfersMatchingClient:notification.object];
}
#pragma mark -
#pragma mark Actions
- (BOOL)validateMenuItem:(NSMenuItem *)item
{
NSInteger tag = item.tag;
NSArray *selectedFileTransfers = [self selectedFileTransfers];
if (selectedFileTransfers.count == 0) {
return NO;
}
/* Begin actual validation. */
switch (tag) {
case 3001: // Start Download
{
for (TDCFileTransferDialogTransferController *fileTransfer in selectedFileTransfers) {
TDCFileTransferDialogTransferStatus transferStatus = fileTransfer.transferStatus;
if (transferStatus == TDCFileTransferDialogTransferStatusStopped ||
transferStatus == TDCFileTransferDialogTransferStatusRecoverableError)
{
return YES;
}
}
return NO;
}
case 3003: // Stop Download
{
for (TDCFileTransferDialogTransferController *fileTransfer in selectedFileTransfers) {
TDCFileTransferDialogTransferStatus transferStatus = fileTransfer.transferStatus;
if (transferStatus == TDCFileTransferDialogTransferStatusConnecting ||
transferStatus == TDCFileTransferDialogTransferStatusReceiving ||
transferStatus == TDCFileTransferDialogTransferStatusIsListeningAsSender ||
transferStatus == TDCFileTransferDialogTransferStatusIsListeningAsReceiver ||
transferStatus == TDCFileTransferDialogTransferStatusSending ||
transferStatus == TDCFileTransferDialogTransferStatusMappingListeningPort ||
transferStatus == TDCFileTransferDialogTransferStatusWaitingForLocalIPAddress ||
transferStatus == TDCFileTransferDialogTransferStatusWaitingForReceiverToAccept ||
transferStatus == TDCFileTransferDialogTransferStatusWaitingForResumeAccept)
{
return YES;
}
}
return NO;
}
case 3004: // Remove Item
{
return YES;
}
case 3005: // Open File
{
for (TDCFileTransferDialogTransferController *fileTransfer in selectedFileTransfers) {
TDCFileTransferDialogTransferStatus transferStatus = fileTransfer.transferStatus;
if (fileTransfer.isSender != NO) {
continue;
}
if (transferStatus == TDCFileTransferDialogTransferStatusComplete) {
return YES;
}
}
return NO;
}
case 3006: // Reveal In Finder
{
for (TDCFileTransferDialogTransferController *fileTransfer in selectedFileTransfers) {
TDCFileTransferDialogTransferStatus transferStatus = fileTransfer.transferStatus;
if (fileTransfer.isSender != NO) {
continue;
}
if (transferStatus == TDCFileTransferDialogTransferStatusComplete) {
return YES;
}
}
return NO;
}
}
return NO; // Default validation to NO.
}
- (void)clear:(id)sender
{
NSArray *stoppedFileTransfers = [self stoppedFileTransfers];
[stoppedFileTransfers makeObjectsPerformSelector:@selector(prepareForPermanentDestruction)];
[self.fileTransfersController removeObjects:stoppedFileTransfers];
[self updateClearButton];
}
- (void)startTransferOfFile:(id)sender
{
NSString *savePath = self.downloadDestinationURLPrivate.path;
NSMutableArray *fileTransfersPending = [NSMutableArray array];
/* Open all file transfers who are senders or have a path */
[self enumerateSelectedFileTransfers:^(TDCFileTransferDialogTransferController *fileTransfer, NSUInteger index, BOOL *stop) {
TDCFileTransferDialogTransferStatus transferStatus = fileTransfer.transferStatus;
if (transferStatus != TDCFileTransferDialogTransferStatusStopped &&
transferStatus != TDCFileTransferDialogTransferStatusRecoverableError)
{
return;
}
if (fileTransfer.isSender || fileTransfer.path != nil) {
[fileTransfer open];
return;
} else if (fileTransfer.path == nil && savePath != nil) {
[fileTransfer openWithPath:savePath];
return;
}
[fileTransfersPending addObject:fileTransfer];
}];
/* If there are file transfers that weren't opened because of a missing
path, then we now prompt the user for where they want to save the files. */
if (fileTransfersPending.count == 0) {
return;
}
NSOpenPanel *openDialog = [NSOpenPanel openPanel];
openDialog.directoryURL = [TPCPathInfo userDownloadsURL];
openDialog.allowsMultipleSelection = NO;
openDialog.canChooseDirectories = YES;
openDialog.canChooseFiles = NO;
openDialog.canCreateDirectories = YES;
openDialog.resolvesAliases = YES;
openDialog.message = TXTLS(@"TDCFileTransferDialog[dcm-w7]");
openDialog.prompt = TXTLS(@"Prompts[xne-79]");
[openDialog beginSheetModalForWindow:self.window completionHandler:^(NSInteger result) {
if (result != NSModalResponseOK) {
return;
}
NSString *path = openDialog.URL.path;
for (TDCFileTransferDialogTransferController *fileTransfer in fileTransfersPending) {
[fileTransfer openWithPath:path];
}
}];
}
- (void)stopTransferOfFile:(id)sender
{
[self enumerateSelectedFileTransfers:^(TDCFileTransferDialogTransferController *fileTransfer, NSUInteger index, BOOL *stop) {
[fileTransfer closeAndPostNotification:NO];
}];
}
- (void)removeTransferFromList:(id)sender
{
NSArray *selectedFileTransfers = [self selectedFileTransfers];
for (TDCFileTransferDialogTransferController *fileTransfer in selectedFileTransfers) {
[fileTransfer prepareForPermanentDestruction];
}
[self.fileTransfersController removeObjects:selectedFileTransfers];
}
- (void)openReceivedFile:(id)sender
{
[self enumerateSelectedFileTransfers:^(TDCFileTransferDialogTransferController *fileTransfer, NSUInteger index, BOOL *stop) {
if (fileTransfer.isSender != NO) {
return;
}
[RZWorkspace() openURL:fileTransfer.fileURL];
}];
}
- (void)revealReceivedFileInFinder:(id)sender
{
[self enumerateSelectedFileTransfers:^(TDCFileTransferDialogTransferController *fileTransfer, NSUInteger index, BOOL *stop) {
if (fileTransfer.isSender != NO) {
return;
}
[RZWorkspace() selectFile:fileTransfer.filePath inFileViewerRootedAtPath:@""];
}];
}
#pragma mark -
#pragma mark Timer
- (void)updateMaintenanceTimerOnMainThread
{
NSArray *activeFileTransfers = [self activeFileTransfers];
if (self.maintenanceTimer.timerIsActive) {
if (activeFileTransfers.count == 0) {
[self.maintenanceTimer stop];
}
} else {
if (activeFileTransfers.count > 0) {
[self.maintenanceTimer start:1.0 onRepeat:YES];
}
}
}
- (void)updateMaintenanceTimer
{
XRPerformBlockSynchronouslyOnMainQueue(^{
[self updateMaintenanceTimerOnMainThread];
});
}
- (void)onMaintenanceTimer
{
NSArray *activeFileTransfers = [self activeFileTransfers];
for (TDCFileTransferDialogTransferController *fileTransfer in activeFileTransfers) {
[fileTransfer onMaintenanceTimer];
}
}
#pragma mark -
#pragma mark Table View Delegate
- (nullable NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(nullable NSTableColumn *)tableColumn row:(NSInteger)row
{
TDCFileTransferDialogTransferController *fileTransfer = self.fileTransfersController.arrangedObjects[row];
TDCFileTransferDialogTableCell *newView =
(TDCFileTransferDialogTableCell *)[tableView makeViewWithIdentifier:@"GroupView" owner:self];
fileTransfer.transferTableCell = newView;
return newView;
}
- (void)tableView:(NSTableView *)tableView didAddRowView:(NSTableRowView *)rowView forRow:(NSInteger)row
{
TDCFileTransferDialogTableCell *tableCell = [tableView viewAtColumn:0 row:row makeIfNecessary:NO];
[tableCell prepareInitialState];
}
#pragma mark -
#pragma mark Network Information
- (nullable NSString *)IPAddress
{
if ([TPCPreferences fileTransferIPAddressDetectionMethod] == TXFileTransferIPAddressMethodManual) {
NSString *userAddress = [TPCPreferences fileTransferManuallyEnteredIPAddress];
if (userAddress.length == 0) {
return nil;
}
return userAddress;
}
return self->_IPAddress;
}
- (void)clearIPAddress
{
self.IPAddress = nil;
[self.IPAddressRequest cancelLookup];
self.IPAddressRequest = nil;
}
- (void)requestIPAddress
{
if (self.IPAddressRequest != nil) {
return;
}
TLOInternetAddressLookup *lookupRequest = [[TLOInternetAddressLookup alloc] initWithDelegate:(id)self];
[lookupRequest performLookup];
self.IPAddressRequest = lookupRequest;
}
- (void)internetAddressLookupReturnedAddress:(NSString *)address
{
self.IPAddress = address;
[self enumerateFileTransferSenders:^(TDCFileTransferDialogTransferController *fileTransfer, BOOL *stop) {
if (fileTransfer.transferStatus != TDCFileTransferDialogTransferStatusWaitingForLocalIPAddress) {
return;
}
[fileTransfer noteIPAddressLookupSucceeded];
}];
self.IPAddressRequest = nil;
}
- (void)internetAddressLookupFailed
{
[self enumerateFileTransferSenders:^(TDCFileTransferDialogTransferController *fileTransfer, BOOL *stop) {
if (fileTransfer.transferStatus != TDCFileTransferDialogTransferStatusWaitingForLocalIPAddress) {
return;
}
[fileTransfer noteIPAddressLookupFailed];
}];
self.IPAddressRequest = nil;
}
#pragma mark -
#pragma mark Navigation
- (TDCFileTransferDialogSelection)navigationSelection
{
return self.navigationControllerCell.selectedSegment;
}
- (void)navigationSelectionDidChange:(id)sender
{
TDCFileTransferDialogSelection selection = self.navigationSelection;
NSPredicate *filterPredicate = nil;
if (selection == TDCFileTransferDialogSelectionSending) {
filterPredicate = [NSPredicate predicateWithFormat:@"isSender == YES"];
} else if (selection == TDCFileTransferDialogSelectionReceiving) {
filterPredicate = [NSPredicate predicateWithFormat:@"isSender == NO"];
}
self.fileTransfersController.filterPredicate = filterPredicate;
}
#pragma mark -
#pragma mark Transfer Search
- (NSUInteger)receiverCount
{
__block NSUInteger receiverCount = 0;
[self enumerateFileTransferReceivers:^(TDCFileTransferDialogTransferController *fileTransfer, BOOL *stop) {
receiverCount += 1;
}];
return receiverCount;
}
- (NSArray *)stoppedFileTransfers
{
return [self fileTransfersMatchingCondition:^BOOL(TDCFileTransferDialogTransferController *fileTransfer) {
TDCFileTransferDialogTransferStatus transferStatus = fileTransfer.transferStatus;
if (transferStatus != TDCFileTransferDialogTransferStatusComplete &&
transferStatus != TDCFileTransferDialogTransferStatusStopped &&
transferStatus != TDCFileTransferDialogTransferStatusFatalError &&
transferStatus != TDCFileTransferDialogTransferStatusRecoverableError)
{
return NO;
}
return YES;
}];
}
- (NSArray *)activeFileTransfers
{
return [self fileTransfersMatchingCondition:^BOOL(TDCFileTransferDialogTransferController *fileTransfer) {
TDCFileTransferDialogTransferStatus transferStatus = fileTransfer.transferStatus;
if (transferStatus != TDCFileTransferDialogTransferStatusReceiving &&
transferStatus != TDCFileTransferDialogTransferStatusSending)
{
return NO;
}
return YES;
}];
}
- (NSArray *)fileTransfersMatchingCondition:(BOOL (NS_NOESCAPE ^)(TDCFileTransferDialogTransferController *fileTransfer))matchCondition
{
NSMutableArray *fileTransfers = [NSMutableArray array];
[self enumerateFileTransfers:^(TDCFileTransferDialogTransferController *fileTransfer, BOOL *stop) {
if (matchCondition(fileTransfer) == NO) {
return;
}
[fileTransfers addObject:fileTransfer];
}];
return [fileTransfers copy];
}
- (nullable TDCFileTransferDialogTransferController *)fileTransferMatchingCondition:(BOOL (NS_NOESCAPE ^)(TDCFileTransferDialogTransferController *fileTransfer))matchCondition
{
__block TDCFileTransferDialogTransferController *fileTransferMatched = nil;
[self enumerateFileTransfers:^(TDCFileTransferDialogTransferController *fileTransfer, BOOL *stop) {
if (matchCondition(fileTransfer) == NO) {
return;
}
fileTransferMatched = fileTransfer;
*stop = YES;
}];
return fileTransferMatched;
}
- (NSArray *)selectedFileTransfers
{
NSMutableArray *selectedFileTransfers = [NSMutableArray array];
[self enumerateSelectedFileTransfers:^(TDCFileTransferDialogTransferController *fileTransfer, NSUInteger index, BOOL *stop) {
[selectedFileTransfers addObject:fileTransfer];
}];
return [selectedFileTransfers copy];
}
- (NSArray *)fileTransfersMatchingClient:(IRCClient *)client
{
NSParameterAssert(client != nil);
return [self fileTransfersMatchingCondition:^BOOL(TDCFileTransferDialogTransferController * _Nonnull fileTransfer) {
return (fileTransfer.client == client);
}];
}
- (void)enumerateSelectedFileTransfers:(void (NS_NOESCAPE ^)(TDCFileTransferDialogTransferController *fileTransfer, NSUInteger index, BOOL *stop))enumerationBlock
{
NSIndexSet *selectedRows = self.fileTransferTable.selectedRowIndexes;
[selectedRows enumerateIndexesUsingBlock:^(NSUInteger index, BOOL *stop) {
TDCFileTransferDialogTransferController *fileTransfer = self.fileTransfersController.arrangedObjects[index];
enumerationBlock(fileTransfer, index, stop);
}];
}
- (void)enumerateFileTransfers:(void (NS_NOESCAPE ^)(TDCFileTransferDialogTransferController *fileTransfer, BOOL *stop))enumerationBlock
{
[self _enumerateFileTransfers:enumerationBlock limitScope:NO limitScopeToSenders:NO];
}
- (void)enumerateFileTransferReceivers:(void (NS_NOESCAPE ^)(TDCFileTransferDialogTransferController *fileTransfer, BOOL *stop))enumerationBlock
{
[self _enumerateFileTransfers:enumerationBlock limitScope:YES limitScopeToSenders:NO];
}
- (void)enumerateFileTransferSenders:(void (NS_NOESCAPE ^)(TDCFileTransferDialogTransferController *fileTransfer, BOOL *stop))enumerationBlock
{
[self _enumerateFileTransfers:enumerationBlock limitScope:YES limitScopeToSenders:YES];
}
- (void)_enumerateFileTransfers:(void (NS_NOESCAPE ^)(TDCFileTransferDialogTransferController *fileTransfer, BOOL *stop))enumerationBlock limitScope:(BOOL)limitScope limitScopeToSenders:(BOOL)limitScopeToSenders
{
NSParameterAssert(enumerationBlock != nil);
for (TDCFileTransferDialogTransferController *fileTransfer in self.fileTransfersController.arrangedObjects) {
if (limitScope && limitScopeToSenders != fileTransfer.isSender) {
continue;
}
BOOL stop = NO;
enumerationBlock(fileTransfer, &stop);
if (stop) {
break;
}
}
}
#pragma mark -
#pragma mark Window Delegate
- (void)windowWillClose:(NSNotification *)note
{
[self.window saveWindowStateForClass:self.class];
}
- (void)hideWindow:(id)sender
{
[self close];
}
@end
#pragma mark -
#pragma mark Destination Folder
@implementation TDCFileTransferDialog (TDCFileTransferDialogDownloadDestinationExtension)
- (nullable NSURL *)downloadDestinationURL
{
return self.downloadDestinationURLPrivate;
}
- (void)startUsingDownloadDestinationURL
{
NSData *bookmark = [RZUserDefaults() dataForKey:@"File Transfers -> File Transfer Download Folder Bookmark"];
if (bookmark == nil) {
return;
}
BOOL resolvedBookmarkIsStale = YES;
NSError *resolvedBookmarkError = nil;
NSURL *resolvedBookmark =
[NSURL URLByResolvingBookmarkData:bookmark
options:NSURLBookmarkResolutionWithSecurityScope
relativeToURL:nil
bookmarkDataIsStale:&resolvedBookmarkIsStale
error:&resolvedBookmarkError];
if (resolvedBookmark == nil) {
LogToConsoleError("Error creating bookmark for URL: %{public}@",
resolvedBookmarkError.localizedDescription);
return;
}
self.downloadDestinationURLPrivate = resolvedBookmark;
if ([self.downloadDestinationURLPrivate startAccessingSecurityScopedResource] == NO) {
LogToConsoleError("Failed to access bookmark");
}
}
- (void)setDownloadDestinationURL:(nullable NSData *)downloadDestinationURL
{
if ( self.downloadDestinationURLPrivate) {
[self.downloadDestinationURLPrivate stopAccessingSecurityScopedResource];
self.downloadDestinationURLPrivate = nil;
}
[RZUserDefaults() setObject:downloadDestinationURL forKey:@"File Transfers -> File Transfer Download Folder Bookmark"];
[self startUsingDownloadDestinationURL];
}
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Dialogs/File Transfers/TDCFileTransferDialogTableCell.m
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2008 - 2010 Satoshi Nakagawa
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "TXGlobalModels.h"
#import "TLOLocalization.h"
#import "TDCFileTransferDialogTransferControllerPrivate.h"
#import "TDCFileTransferDialogTableCellPrivate.h"
NS_ASSUME_NONNULL_BEGIN
#define _filenameFieldWithProgressBarYCord 4
#define _filenameFieldWithoutProgressBarYCord 12
#define _transferInfoFieldWithProgressBarYCord 6
#define _transferInfoFieldWithoutProgressBarYCord 16
@interface TDCFileTransferDialogTableCell ()
@property (readonly) TDCFileTransferDialogTransferController *cellItem;
@property (nonatomic, weak) IBOutlet NSProgressIndicator *progressIndicator;
@property (nonatomic, weak) IBOutlet NSImageView *fileIconView;
@property (nonatomic, weak) IBOutlet NSTextField *filenameTextField;
@property (nonatomic, weak) IBOutlet NSTextField *filesizeTextField;
@property (nonatomic, weak) IBOutlet NSTextField *transferProgressTextField;
@property (nonatomic, weak) IBOutlet NSLayoutConstraint *filenameTextFieldConstraint;
@property (nonatomic, weak) IBOutlet NSLayoutConstraint *transferProgressTextFieldConstraint;
@property (readonly) BOOL isReceiving;
@property (readonly) TDCFileTransferDialogTransferStatus transferStatus;
@property (readonly) uint64_t processedFilesize;
@property (readonly) uint64_t totalFilesize;
@property (readonly) uint64_t currentRecord;
@property (readonly, copy) NSArray *speedRecords;
@property (readonly, copy, nullable) NSString *errorMessageDescription;
@property (readonly, copy, nullable) NSString *path;
@property (readonly, copy) NSString *filename;
@property (readonly, copy, nullable) NSString *filePath;
@property (readonly, copy) NSString *hostAddress;
@property (readonly, copy) NSString *peerNickname;
@property (readonly) uint16_t hostPort;
@end
@implementation TDCFileTransferDialogTableCell
#pragma mark -
#pragma mark Status Information
- (void)prepareInitialState
{
NSString *filename = self.filename;
self.filenameTextField.stringValue = filename;
uint64_t totalFilesize = self.totalFilesize;
NSString *totalFilesizeString = [NSByteCountFormatter stringFromByteCountWithPaddedDigits:totalFilesize];
self.filesizeTextField.stringValue = totalFilesizeString;
self.progressIndicator.doubleValue = 0;
self.progressIndicator.minValue = 0;
self.progressIndicator.maxValue = totalFilesize;
NSImage *iconImage = [RZWorkspace() iconForFileType:filename.pathExtension];
self.fileIconView.image = iconImage;
[self reloadStatusInformation];
}
- (void)reloadStatusInformation
{
XRPerformBlockSynchronouslyOnMainQueue(^{
[self _reloadStatusInformation];
});
}
- (void)_reloadStatusInformation
{
TDCFileTransferDialogTransferStatus transferStatus = self.transferStatus;
BOOL transferIsStopped = (transferStatus == TDCFileTransferDialogTransferStatusComplete ||
transferStatus == TDCFileTransferDialogTransferStatusFatalError ||
transferStatus == TDCFileTransferDialogTransferStatusRecoverableError ||
transferStatus == TDCFileTransferDialogTransferStatusStopped ||
transferStatus == TDCFileTransferDialogTransferStatusIsListeningAsSender ||
transferStatus == TDCFileTransferDialogTransferStatusIsListeningAsReceiver ||
transferStatus == TDCFileTransferDialogTransferStatusInitializing ||
transferStatus == TDCFileTransferDialogTransferStatusMappingListeningPort ||
transferStatus == TDCFileTransferDialogTransferStatusWaitingForLocalIPAddress ||
transferStatus == TDCFileTransferDialogTransferStatusWaitingForReceiverToAccept ||
transferStatus == TDCFileTransferDialogTransferStatusWaitingForResumeAccept);
uint64_t processedFilesize = self.processedFilesize;
if (transferIsStopped) {
if (self.progressIndicator.hidden == NO) {
self.progressIndicator.hidden = YES;
self.filenameTextFieldConstraint.constant = _filenameFieldWithoutProgressBarYCord;
self.transferProgressTextFieldConstraint.constant = _transferInfoFieldWithoutProgressBarYCord;
[self layoutSubtreeIfNeeded];
}
} else {
if (self.progressIndicator.hidden) {
self.progressIndicator.hidden = NO;
self.filenameTextFieldConstraint.constant = _filenameFieldWithProgressBarYCord;
self.transferProgressTextFieldConstraint.constant = _transferInfoFieldWithProgressBarYCord;
[self layoutSubtreeIfNeeded];
}
}
if (transferIsStopped == NO) {
if (transferStatus == TDCFileTransferDialogTransferStatusConnecting) {
self.progressIndicator.indeterminate = YES;
[self.progressIndicator startAnimation:nil];
} else {
self.progressIndicator.indeterminate = NO;
self.progressIndicator.doubleValue = self.processedFilesize;
}
}
switch (transferStatus) {
case TDCFileTransferDialogTransferStatusStopped:
{
if (self.isReceiving) {
self.transferProgressTextField.stringValue = TXTLS(@"TDCFileTransferDialog[jvh-u7]", self.peerNickname);
} else {
self.transferProgressTextField.stringValue = TXTLS(@"TDCFileTransferDialog[w3h-p8]", self.peerNickname);
}
break;
}
case TDCFileTransferDialogTransferStatusMappingListeningPort:
{
if (self.isReceiving) {
self.transferProgressTextField.stringValue = TXTLS(@"TDCFileTransferDialog[495-90]", self.peerNickname);
} else {
self.transferProgressTextField.stringValue = TXTLS(@"TDCFileTransferDialog[j1z-88]", self.peerNickname);
}
break;
}
case TDCFileTransferDialogTransferStatusWaitingForLocalIPAddress:
{
if (self.isReceiving) {
self.transferProgressTextField.stringValue = TXTLS(@"TDCFileTransferDialog[6t1-mb]", self.peerNickname);
} else {
self.transferProgressTextField.stringValue = TXTLS(@"TDCFileTransferDialog[onl-av]", self.peerNickname);
}
break;
}
case TDCFileTransferDialogTransferStatusInitializing:
{
if (self.isReceiving) {
self.transferProgressTextField.stringValue = TXTLS(@"TDCFileTransferDialog[42z-mg]", self.peerNickname);
} else {
self.transferProgressTextField.stringValue = TXTLS(@"TDCFileTransferDialog[pcv-kg]", self.peerNickname);
}
break;
}
case TDCFileTransferDialogTransferStatusIsListeningAsSender:
{
self.transferProgressTextField.stringValue = TXTLS(@"TDCFileTransferDialog[ca5-2v]", self.peerNickname);
break;
}
case TDCFileTransferDialogTransferStatusIsListeningAsReceiver:
{
self.transferProgressTextField.stringValue = TXTLS(@"TDCFileTransferDialog[pip-z6]", self.peerNickname);
break;
}
case TDCFileTransferDialogTransferStatusFatalError:
case TDCFileTransferDialogTransferStatusRecoverableError:
{
self.transferProgressTextField.stringValue = self.errorMessageDescription;
break;
}
case TDCFileTransferDialogTransferStatusComplete:
{
if (self.isReceiving) {
self.transferProgressTextField.stringValue = TXTLS(@"TDCFileTransferDialog[6gu-za]", self.peerNickname);
} else {
self.transferProgressTextField.stringValue = TXTLS(@"TDCFileTransferDialog[rx7-xy]", self.peerNickname);
}
break;
}
case TDCFileTransferDialogTransferStatusSending:
case TDCFileTransferDialogTransferStatusReceiving:
{
/* Format time remaining */
NSTimeInterval timeRemaining = 0;
NSString *timeRemainingString = nil;
uint64_t currentSpeed = self.currentSpeed;
if (currentSpeed > 0) {
timeRemaining = ((self.totalFilesize - processedFilesize) / currentSpeed);
if (timeRemaining > 0) {
timeRemainingString = TXHumanReadableTimeInterval(timeRemaining, YES, (NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond));
}
}
/* Update status */
NSString *totalFilesizeString = self.filesizeTextField.stringValue;
NSString *currentSpeedString = [NSByteCountFormatter stringFromByteCountWithPaddedDigits:currentSpeed];
NSString *processedFilesizeString = [NSByteCountFormatter stringFromByteCountWithPaddedDigits:processedFilesize];
NSString *statusString = nil;
if (self.isReceiving) {
if (timeRemainingString) {
statusString = TXTLS(@"TDCFileTransferDialog[9xn-7j]", processedFilesizeString, totalFilesizeString, currentSpeedString, self.peerNickname, timeRemainingString);
} else {
statusString = TXTLS(@"TDCFileTransferDialog[7dk-lp]", processedFilesizeString, totalFilesizeString, currentSpeedString, self.peerNickname);
}
} else {
if (timeRemainingString) {
statusString = TXTLS(@"TDCFileTransferDialog[u17-ql]", processedFilesizeString, totalFilesizeString, currentSpeedString, self.peerNickname, timeRemainingString);
} else {
statusString = TXTLS(@"TDCFileTransferDialog[nvm-nd]", processedFilesizeString, totalFilesizeString, currentSpeedString, self.peerNickname);
}
}
self.transferProgressTextField.stringValue = statusString;
break;
}
case TDCFileTransferDialogTransferStatusConnecting:
{
self.transferProgressTextField.stringValue = TXTLS(@"TDCFileTransferDialog[7nf-fr]", self.peerNickname);
break;
}
case TDCFileTransferDialogTransferStatusWaitingForReceiverToAccept:
{
self.transferProgressTextField.stringValue = TXTLS(@"TDCFileTransferDialog[cku-24]", self.peerNickname);
break;
}
case TDCFileTransferDialogTransferStatusWaitingForResumeAccept:
{
self.transferProgressTextField.stringValue = TXTLS(@"TDCFileTransferDialog[gxq-zu]", self.peerNickname);
break;
}
}
/* Update clear button */
[self updateClearButton];
}
#pragma mark -
#pragma mark Proxy Methods
- (void)updateClearButton
{
[self.cellItem updateClearButton];
}
- (void)onMaintenanceTimer
{
[self.cellItem onMaintenanceTimer];
}
#pragma mark -
#pragma mark Properties
- (TDCFileTransferDialogTransferController *)cellItem
{
return self.objectValue;
}
- (TDCFileTransferDialogTransferStatus)transferStatus
{
return self.cellItem.transferStatus;
}
- (BOOL)isReceiving
{
return (self.cellItem.isSender == NO);
}
- (nullable NSString *)path
{
return self.cellItem.path;
}
- (NSString *)filename
{
return self.cellItem.filename;
}
- (nullable NSString *)filePath
{
return self.cellItem.filePath;
}
- (NSString *)peerNickname
{
return self.cellItem.peerNickname;
}
- (nullable NSString *)errorMessageDescription
{
return self.cellItem.errorMessageDescription;
}
- (NSString *)hostAddress
{
return self.cellItem.hostAddress;
}
- (uint16_t)hostPort
{
return self.cellItem.hostPort;
}
- (uint64_t)totalFilesize
{
return self.cellItem.totalFilesize;
}
- (uint64_t)processedFilesize
{
return self.cellItem.processedFilesize;
}
- (uint64_t)currentRecord
{
return self.cellItem.currentRecord;
}
- (uint64_t)currentSpeed
{
NSArray *speedRecords = self.speedRecords;
if (speedRecords.count == 0) {
return 0;
}
uint64_t totalTransferred = 0;
for (NSNumber *record in speedRecords) {
totalTransferred += record.unsignedLongLongValue;
}
return (totalTransferred / speedRecords.count);
}
- (NSArray *)speedRecords
{
return self.cellItem.speedRecords;
}
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Dialogs/File Transfers/TDCFileTransferDialogTransferController.m
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2008 - 2010 Satoshi Nakagawa
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "NSObjectHelperPrivate.h"
#import "GCDAsyncSocket.h"
#import "TXGlobalModels.h"
#import "IRCClientPrivate.h"
#import "TPCPathInfo.h"
#import "TPCPreferencesLocal.h"
#import "TLOEncryptionManagerPrivate.h"
#import "TLOLocalization.h"
#import "TDCFileTransferDialogTableCellPrivate.h"
#import "TDCFileTransferDialogTransferControllerPrivate.h"
#import "TDCFileTransferDialogInternal.h"
NS_ASSUME_NONNULL_BEGIN
#define RECORDS_LENGTH 10
#define MAX_QUEUE_SIZE 2
#define BUFFER_SIZE (1024 * 64)
#define RATE_LIMIT (1024 * 1024 * 10)
#define _connectTimeout 30.0
#define _sendDataTimeout 30.0
#define _resumeAcceptTimeout 10.0
@interface TDCFileTransferDialogTransferController ()
@property (nonatomic, strong, readwrite) IRCClient *client;
@property (nonatomic, copy, readwrite) NSString *clientId;
@property (nonatomic, assign, readwrite) BOOL isResume;
@property (nonatomic, assign, readwrite) BOOL isReversed;
@property (nonatomic, assign, readwrite) BOOL isSender;
@property (nonatomic, assign, readwrite) TDCFileTransferDialogTransferStatus transferStatus;
@property (nonatomic, assign, readwrite) uint64_t totalFilesize;
@property (nonatomic, assign, readwrite) uint64_t processedFilesize;
@property (nonatomic, assign, readwrite) uint64_t currentRecord;
@property (nonatomic, strong) NSMutableArray *speedRecordsPrivate;
@property (nonatomic, copy, readwrite, nullable) NSString *errorMessageDescription;
@property (nonatomic, copy, readwrite, nullable) NSString *path;
@property (nonatomic, copy, readwrite) NSString *filename;
@property (nonatomic, copy, readwrite) NSString *hostAddress;
@property (nonatomic, copy, readwrite) NSString *peerNickname;
@property (nonatomic, copy, readwrite, nullable) NSString *transferToken;
@property (nonatomic, copy, readwrite) NSString *uniqueIdentifier;
@property (nonatomic, assign, readwrite) uint16_t hostPort;
@property (nonatomic, strong, nullable) NSFileHandle *fileHandle;
@property (nonatomic, strong, nullable) XRPortMapper *portMapping;
@property (nonatomic, assign) NSUInteger sendQueueSize;
@property (nonatomic, strong, nullable) dispatch_queue_t serverDispatchQueue;
@property (nonatomic, strong, nullable) dispatch_queue_t serverSocketQueue;
@property (nonatomic, strong, nullable) GCDAsyncSocket *listeningServer;
@property (nonatomic, strong, nullable) GCDAsyncSocket *listeningServerConnectedClient;
@property (nonatomic, strong, nullable) GCDAsyncSocket *connectionToRemoteServer;
@property (nonatomic, strong, nullable) id transferProgressHandler; // Used to prevent system sleep
@property (readonly) uint64_t currentFilesize;
@property (readonly) TDCFileTransferDialog *transferDialog;
@property (readonly, nullable) GCDAsyncSocket *readSocket;
@property (readonly, nullable) GCDAsyncSocket *writeSocket;
@end
@implementation TDCFileTransferDialogTransferController
#pragma mark -
#pragma mark Initialization
+ (nullable instancetype)receiverForClient:(IRCClient *)client nickname:(NSString *)nickname address:(NSString *)hostAddress port:(uint16_t)hostPort filename:(NSString *)filename filesize:(uint64_t)totalFilesize token:(nullable NSString *)transferToken
{
NSParameterAssert(client != nil);
NSParameterAssert(nickname != nil);
NSParameterAssert(hostAddress != nil);
NSParameterAssert(filename != nil);
/* Construct controller */
TDCFileTransferDialogTransferController *controller = [[self alloc] initWithClient:client];
if (transferToken.length > 0) {
controller.transferToken = transferToken;
controller.isReversed = YES;
}
controller.isSender = NO;
controller.peerNickname = nickname;
controller.hostAddress = hostAddress;
controller.hostPort = hostPort;
controller.filename = filename;
controller.totalFilesize = totalFilesize;
return controller;
}
+ (nullable instancetype)senderForClient:(IRCClient *)client nickname:(NSString *)nickname path:(NSString *)path
{
NSParameterAssert(client != nil);
NSParameterAssert(nickname != nil);
NSParameterAssert(path != nil);
NSString *filename = path.lastPathComponent;
#if TEXTUAL_BUILT_WITH_ADVANCED_ENCRYPTION == 1
if ([TPCPreferences textEncryptionIsEnabled]) {
/* Ask whether we should be allowed to add the file. */
BOOL allowWithOTR = [sharedEncryptionManager()
safeToTransferFile:filename
to:[client encryptionAccountNameForUser:nickname]
from:[client encryptionAccountNameForLocalUser]
isIncomingFileTransfer:NO];
if (allowWithOTR == NO) {
return nil; // This operation is not allowed...
}
}
#endif
/* Gather file information */
NSDictionary *fileAttributes = [RZFileManager() attributesOfItemAtPath:path error:NULL];
if (fileAttributes == nil) {
return nil;
}
uint64_t totalFilesize = [fileAttributes fileSize];
if (totalFilesize == 0) {
LogToConsoleError("Fatal error: Cannot create sender because filesize == 0");
return nil;
}
NSString *filePath = path.stringByDeletingLastPathComponent;
/* Construct controller */
TDCFileTransferDialogTransferController *controller = [[self alloc] initWithClient:client];
controller.isReversed = [TPCPreferences fileTransferRequestsAreReversed];
controller.isSender = YES;
controller.peerNickname = nickname;
controller.path = filePath;
controller.filename = filename;
controller.totalFilesize = totalFilesize;
return controller;
}
- (instancetype)init
{
[self doesNotRecognizeSelector:_cmd];
return nil;
}
- (instancetype)initWithClient:(IRCClient *)client
{
NSParameterAssert(client != nil);
if ((self = [super init])) {
self.client = client;
self.clientId = client.uniqueIdentifier;
[self prepareInitialState];
return self;
}
return nil;
}
- (void)prepareInitialState
{
self.speedRecordsPrivate = [NSMutableArray array];
self.transferStatus = TDCFileTransferDialogTransferStatusStopped;
self.uniqueIdentifier = [NSString stringWithUUID];
[RZNotificationCenter() addObserver:self selector:@selector(clientDisconnected:) name:IRCClientDidDisconnectNotification object:self.client];
[RZNotificationCenter() addObserver:self selector:@selector(peerNicknameChanged:) name:IRCClientUserNicknameChangedNotification object:self.client];
}
- (void)prepareForPermanentDestruction
{
self.transferTableCell = nil;
[self closeAndPostNotification:NO];
[RZNotificationCenter() removeObserver:self];
}
#pragma mark -
#pragma mark Error Handling
- (void)failWithNoSpaceLeftOnDevice
{
[self closeWithLocalizedError:TXTLS(@"TDCFileTransferDialog[79f-s0]")];
}
- (void)closeWithLocalizedError:(NSString *)errorLocalization
{
[self closeWithLocalizedError:errorLocalization description:nil isFatalError:NO];
}
- (void)closeWithLocalizedError:(NSString *)errorLocalization isFatalError:(BOOL)isFatalError
{
[self closeWithLocalizedError:errorLocalization description:nil isFatalError:isFatalError];
}
- (void)closeWithLocalizedError:(NSString *)errorLocalization description:(nullable NSString *)errorDescription
{
[self closeWithLocalizedError:errorLocalization description:errorDescription isFatalError:NO];
}
- (void)closeWithLocalizedError:(NSString *)errorLocalization description:(nullable NSString *)errorDescription isFatalError:(BOOL)isFatalError
{
NSParameterAssert(errorLocalization != nil);
if (errorDescription == nil) {
self.errorMessageDescription = TXTLS(errorLocalization, self.peerNickname);
} else {
self.errorMessageDescription = TXTLS(errorLocalization, self.peerNickname, errorDescription);
}
if (isFatalError) {
self.transferStatus = TDCFileTransferDialogTransferStatusFatalError;
} else {
self.transferStatus = TDCFileTransferDialogTransferStatusRecoverableError;
}
[self close];
}
#pragma mark -
#pragma mark Dispatch Queue Management
- (void)createDispatchQueues
{
NSString *uniqueId = [NSString stringWithUUID];
NSString *dispatchQueueName = [NSString stringWithFormat:@"Textual.TDCFileTransferDialogTransferController.DCC-SocketDispatchQueue-%@", uniqueId];
self.serverDispatchQueue =
XRCreateDispatchQueueWithPriority(dispatchQueueName.UTF8String, DISPATCH_QUEUE_SERIAL, QOS_CLASS_DEFAULT);
NSString *socketQueueName = [NSString stringWithFormat:@"Textual.TDCFileTransferDialogTransferController.DCC-SocketReadWriteQueue-%@", uniqueId];
self.serverSocketQueue =
XRCreateDispatchQueueWithPriority(socketQueueName.UTF8String, DISPATCH_QUEUE_SERIAL, QOS_CLASS_DEFAULT);
}
- (void)destroyDispatchQueues
{
self.serverDispatchQueue = nil;
self.serverSocketQueue = nil;
}
#pragma mark -
#pragma mark Opening/Closing Transfer
- (void)disableSystemSleep
{
self.transferProgressHandler = [RZProcessInfo() beginActivityWithOptions:NSActivityUserInitiated reason:@"Transferring file"];
}
- (void)enableSystemSleep
{
if (self.transferProgressHandler == nil) {
return;
}
[RZProcessInfo() endActivity:self.transferProgressHandler];
self.transferProgressHandler = nil;
}
- (BOOL)receiveUnencryptedFile
{
#if TEXTUAL_BUILT_WITH_ADVANCED_ENCRYPTION == 1
if ([TPCPreferences textEncryptionIsEnabled]) {
BOOL allowWithOTR = [sharedEncryptionManager()
safeToTransferFile:self.filename
to:[self.client encryptionAccountNameForUser:self.peerNickname]
from:[self.client encryptionAccountNameForLocalUser]
isIncomingFileTransfer:YES];
if (allowWithOTR == NO) {
return NO; // This operation is not allowed...
}
}
#endif
return YES;
}
- (void)open
{
[self openWithPath:nil];
}
- (void)openWithPathOrUserDownloads
{
NSString *path = nil;
if (self.path == nil) {
path = [TPCPathInfo userDownloads];
}
[self openWithPath:path];
}
- (void)openWithPath:(nullable NSString *)path
{
if (self.path == nil) {
self.path = path;
}
if (self.client.isLoggedIn == NO) {
[self _closeWithClientDisconnectedError];
return;
}
if (self.isSender) {
[self openTransfer];
} else {
if ([self receiveUnencryptedFile] == NO) {
return;
}
[self sendTransferResumeRequestToClient];
}
}
- (void)openTransfer
{
if (self.isSender) {
if (self.isReversed) {
[self updateIPAddress];
} else {
[self openConnectionAsServer];
}
} else {
if (self.isReversed) {
[self openConnectionAsServer];
} else {
[self openConnectionToHost];
}
}
}
- (void)openConnectionToHost
{
[self closeAndPostNotification:NO];
[self resetProperties];
[self createDispatchQueues];
self.transferStatus = TDCFileTransferDialogTransferStatusConnecting;
GCDAsyncSocket *connectionToRemoteServer =
[[GCDAsyncSocket alloc] initWithDelegate:(id)self
delegateQueue:self.serverDispatchQueue
socketQueue:self.serverSocketQueue];
NSError *connectionError = nil;
BOOL isConnected = NO;
/* Use the interface of the configured IP address instead of the default. */
/* Default interface is used if IP address is not found locally. */
NSString *networkInterface = [self networkInterfaceMatchingAddress];
if (networkInterface) {
isConnected = [connectionToRemoteServer connectToHost:self.hostAddress onPort:self.hostPort viaInterface:networkInterface withTimeout:_connectTimeout error:&connectionError];
} else {
isConnected = [connectionToRemoteServer connectToHost:self.hostAddress onPort:self.hostPort withTimeout:_connectTimeout error:&connectionError];
}
if (isConnected == NO) {
if (connectionError) {
LogToConsoleError("DCC Connect Error: %{public}@", connectionError.localizedDescription);
}
[self closeWithLocalizedError:@"TDCFileTransferDialog[fn8-sx]"];
return;
}
self.connectionToRemoteServer = connectionToRemoteServer;
[self disableSystemSleep];
}
- (void)openConnectionAsServer
{
[self closeAndPostNotification:NO];
[self resetProperties];
[self createDispatchQueues];
self.transferStatus = TDCFileTransferDialogTransferStatusInitializing;
self.hostPort = [TPCPreferences fileTransferPortRangeStart];
while ([self tryToOpenConnectionAsServer] == NO) {
self.hostPort += 1;
if (self.hostPort > [TPCPreferences fileTransferPortRangeEnd]) {
[self closeWithLocalizedError:@"TDCFileTransferDialog[vxc-sd]"];
return;
}
}
[self disableSystemSleep];
}
- (BOOL)tryToOpenConnectionAsServer
{
GCDAsyncSocket *listeningServer =
[[GCDAsyncSocket alloc] initWithDelegate:(id)self
delegateQueue:self.serverDispatchQueue
socketQueue:self.serverSocketQueue];
BOOL isActive = [listeningServer acceptOnPort:self.hostPort error:NULL];
if (isActive == NO) {
return NO;
}
self.listeningServer = listeningServer;
/* Try to map the port */
XRPortMapper *portMapping = [[XRPortMapper alloc] initWithPort:self.hostPort];
portMapping.mapTCP = YES;
portMapping.mapUDP = NO;
portMapping.desiredPublicPort = self.hostPort;
self.portMapping = portMapping;
[RZNotificationCenter() addObserver:self selector:@selector(portMapperDidFinishWork:) name:XRPortMapperDidChangedNotification object:self.portMapping];
self.transferStatus = TDCFileTransferDialogTransferStatusMappingListeningPort;
if ([self.portMapping open] == NO) {
[self portMapperDidFinishWork:nil];
}
return YES;
}
- (nullable NSString *)networkInterfaceMatchingAddress
{
return [TPCPreferences fileTransferIPAddressInterfaceName];
}
- (void)portMapperDidFinishWork:(NSNotification *)aNotification
{
NSAssertReturn(self.transferStatus == TDCFileTransferDialogTransferStatusMappingListeningPort);
if (self.portMapping.isMapped) {
[self updateIPAddress];
LogToConsoleInfo("Successful port mapping on port %{public}hu", self.hostPort);
return;
}
LogToConsoleError("Port mapping failed with error code: %{public}i", self.portMapping.error);
if (self.isReversed) {
[self closeWithLocalizedError:@"TDCFileTransferDialog[vxc-sd]"];
return;
}
/* If mapping fails, we silently fail */
/* We tried and it was successful, then that is good, but if we
did not, still start listening just incase other conditions allow
the transfer to still take place. */
[self updateIPAddress];
}
- (void)updateIPAddress
{
LogStackTraceWithType(LogToConsoleTypeDebug);
NSString *address = self.transferDialog.IPAddress;
LogToConsoleDebug("TDCFileTransferDialog cached IP address: %{private}@", address);
TXFileTransferIPAddressMethodDetection detectionMethod = [TPCPreferences fileTransferIPAddressDetectionMethod];
BOOL manuallyDetect = (detectionMethod == TXFileTransferIPAddressMethodManual);
if (address == nil && manuallyDetect == NO) {
NSString *publicAddress = self.portMapping.publicAddress;
LogToConsoleDebug("Port mapper public IP address: %{private}@", publicAddress);
if (publicAddress.isIPAddress) {
self.transferDialog.IPAddress = publicAddress;
address = publicAddress;
}
}
/* Request address? */
if (address == nil) {
if (manuallyDetect || detectionMethod == TXFileTransferIPAddressMethodRouterOnly) {
LogToConsoleError("User has set IP address detection to be manual but have no address set");
[self noteIPAddressLookupFailed];
} else {
LogToConsoleDebug("Performing IP address lookup using the Internet");
[self.transferDialog requestIPAddress];
self.transferStatus = TDCFileTransferDialogTransferStatusWaitingForLocalIPAddress;
}
return;
}
[self noteIPAddressLookupSucceeded];
}
- (void)closePortMapping
{
if (self.portMapping == nil) {
return;
}
[RZNotificationCenter() removeObserver:self name:XRPortMapperDidChangedNotification object:self.portMapping];
XRPerformBlockSynchronouslyOnMainQueue(^{
[self.portMapping close];
self.portMapping = nil;
});
}
- (void)noteIPAddressLookupSucceeded
{
LogStackTraceWithType(LogToConsoleTypeDebug);
if (self.isSender) {
if (self.isReversed) {
self.transferStatus = TDCFileTransferDialogTransferStatusWaitingForReceiverToAccept;
} else {
self.transferStatus = TDCFileTransferDialogTransferStatusIsListeningAsSender;
}
} else {
if (self.isReversed) {
self.transferStatus = TDCFileTransferDialogTransferStatusIsListeningAsReceiver;
} else {
return;
}
}
[self sendTransferRequestToClient];
}
- (void)noteIPAddressLookupFailed
{
[self closeWithLocalizedError:@"TDCFileTransferDialog[47s-1s]"];
}
- (void)didReceiveResumeRequest:(uint64_t)proposedPosition
{
uint64_t currentFilesize = self.currentFilesize;
if (proposedPosition == 0 || currentFilesize < proposedPosition) {
return;
}
self.isResume = YES;
self.processedFilesize = proposedPosition;
[self sendTransferResumeAcceptToClient];
}
- (void)didReceiveResumeAccept:(uint64_t)proposedPosition
{
[self cancelPerformRequestsWithSelector:@selector(transferResumeRequestTimeout) object:nil];
uint64_t currentFilesize = self.currentFilesize;
if (currentFilesize != proposedPosition) {
[self closeWithLocalizedError:@"TDCFileTransferDialog[0ov-tr]" isFatalError:YES];
return;
}
self.isResume = YES;
self.processedFilesize = currentFilesize;
[self openTransfer];
}
- (void)didReceiveSendRequest:(NSString *)hostAddress hostPort:(uint16_t)hostPort
{
NSParameterAssert(hostAddress != nil);
self.hostAddress = hostAddress;
self.hostPort = hostPort;
self.processedFilesize = 0;
[self openConnectionToHost];
}
- (void)buildTransferToken
{
NSUInteger loopedCount = 0;
do {
NSString *transferToken = [NSString stringWithUnsignedInteger:TXRandomNumber(9999)];
BOOL transferExists = [self.transferDialog fileTransferExistsWithToken:transferToken];
if (transferExists == NO) {
self.transferToken = transferToken;
break;
}
loopedCount += 1;
} while (loopedCount < 300);
}
- (void)sendTransferRequestToClient
{
if (self.isSender) {
uint64_t currentFilesize = self.currentFilesize;
if (self.isReversed) {
[self buildTransferToken];
[self.client sendFile:self.peerNickname port:0 filename:self.filename filesize:currentFilesize token:self.transferToken];
} else {
[self.client sendFile:self.peerNickname port:self.hostPort filename:self.filename filesize:currentFilesize token:nil];
}
} else {
if (self.isReversed) {
[self.client sendFile:self.peerNickname port:self.hostPort filename:self.filename filesize:self.totalFilesize token:self.transferToken];
}
}
}
- (void)sendTransferResumeRequestToClient
{
uint64_t currentFilesize = self.currentFilesize;
if (currentFilesize == 0 || currentFilesize > self.totalFilesize) {
[self transferResumeRequestTimeout];
return;
}
[self performSelectorInCommonModes:@selector(transferResumeRequestTimeout) withObject:nil afterDelay:_resumeAcceptTimeout];
self.transferStatus = TDCFileTransferDialogTransferStatusWaitingForResumeAccept;
if (self.isReversed) {
[self.client sendFileResume:self.peerNickname port:0 filename:self.filename filesize:currentFilesize token:self.transferToken];
} else {
[self.client sendFileResume:self.peerNickname port:self.hostPort filename:self.filename filesize:currentFilesize token:nil];
}
}
- (void)sendTransferResumeAcceptToClient
{
if (self.isReversed) {
[self.client sendFileResumeAccept:self.peerNickname port:0 filename:self.filename filesize:self.processedFilesize token:self.transferToken];
} else {
[self.client sendFileResumeAccept:self.peerNickname port:self.hostPort filename:self.filename filesize:self.processedFilesize token:nil];
}
}
- (void)transferResumeRequestTimeout
{
[self openTransfer];
}
- (void)peerNicknameChanged:(NSNotification *)notification
{
NSDictionary *userInfo = notification.userInfo;
NSString *oldNickname = userInfo[@"oldNickname"];
if ([self.peerNickname isEqualToString:oldNickname] == NO) {
return;
}
self.peerNickname = userInfo[@"newNickname"];
}
- (void)clientDisconnected:(NSNotification *)notification
{
[self closeWithClientDisconnectedError];
}
- (void)closeWithClientDisconnectedError
{
/* If the controller is already sending or receiving data, then a connection
is already established to the peer which can function without a connection
to IRC. If data is not being transferred then fail immediately. */
TDCFileTransferDialogTransferStatus transferStatus = self.transferStatus;
if (transferStatus != TDCFileTransferDialogTransferStatusConnecting &&
transferStatus != TDCFileTransferDialogTransferStatusInitializing &&
transferStatus != TDCFileTransferDialogTransferStatusIsListeningAsReceiver &&
transferStatus != TDCFileTransferDialogTransferStatusIsListeningAsSender &&
transferStatus != TDCFileTransferDialogTransferStatusMappingListeningPort &&
transferStatus != TDCFileTransferDialogTransferStatusWaitingForLocalIPAddress &&
transferStatus != TDCFileTransferDialogTransferStatusWaitingForReceiverToAccept &&
transferStatus != TDCFileTransferDialogTransferStatusWaitingForResumeAccept)
{
return;
}
[self _closeWithClientDisconnectedError];
}
- (void)_closeWithClientDisconnectedError
{
[self closeWithLocalizedError:@"TDCFileTransferDialog[12p-0v]" isFatalError:NO];
}
- (void)close
{
[self closeAndPostNotification:YES];
}
- (void)closeAndPostNotification:(BOOL)postNotification
{
[self cancelPerformRequests];
if ( self.listeningServer) {
[self.listeningServer disconnect];
self.listeningServer = nil;
}
if ( self.listeningServerConnectedClient) {
[self.listeningServerConnectedClient disconnect];
self.listeningServerConnectedClient = nil;
}
if ( self.connectionToRemoteServer) {
[self.connectionToRemoteServer disconnect];
self.connectionToRemoteServer = nil;
}
[self destroyDispatchQueues];
[self closePortMapping];
[self closeFileHandle];
if (self.transferStatus != TDCFileTransferDialogTransferStatusComplete &&
self.transferStatus != TDCFileTransferDialogTransferStatusFatalError &&
self.transferStatus != TDCFileTransferDialogTransferStatusRecoverableError)
{
self.transferStatus = TDCFileTransferDialogTransferStatusStopped;
}
if (postNotification) {
if (self.transferStatus == TDCFileTransferDialogTransferStatusFatalError ||
self.transferStatus == TDCFileTransferDialogTransferStatusRecoverableError)
{
if (self.isSender) {
[self.client notifyFileTransfer:TXNotificationTypeFileTransferSendFailed nickname:self.peerNickname filename:self.filename filesize:self.totalFilesize requestIdentifier:self.uniqueIdentifier];
} else {
[self.client notifyFileTransfer:TXNotificationTypeFileTransferReceiveFailed nickname:self.peerNickname filename:self.filename filesize:self.totalFilesize requestIdentifier:self.uniqueIdentifier];
}
}
else if (self.transferStatus == TDCFileTransferDialogTransferStatusComplete)
{
if (self.isSender) {
[self.client notifyFileTransfer:TXNotificationTypeFileTransferSendSuccessful nickname:self.peerNickname filename:self.filename filesize:self.totalFilesize requestIdentifier:self.uniqueIdentifier];
} else {
[self.client notifyFileTransfer:TXNotificationTypeFileTransferReceiveSuccessful nickname:self.peerNickname filename:self.filename filesize:self.totalFilesize requestIdentifier:self.uniqueIdentifier];
}
}
}
[self.transferDialog updateMaintenanceTimer];
[self enableSystemSleep];
}
#pragma mark -
#pragma mark Timer
- (void)onMaintenanceTimer
{
NSAssertReturn(self.transferStatus == TDCFileTransferDialogTransferStatusReceiving ||
self.transferStatus == TDCFileTransferDialogTransferStatusSending);
XRPerformBlockSynchronouslyOnQueue(self.serverDispatchQueue, ^{
@synchronized(self.speedRecords) {
[self.speedRecordsPrivate addObject:@(self.currentRecord)];
if (self.speedRecordsPrivate.count > RECORDS_LENGTH) {
[self.speedRecordsPrivate removeObjectAtIndex:0];
}
}
self.currentRecord = 0;
[self reloadStatusInformation];
});
[self send];
}
#pragma mark -
#pragma mark File Handle
- (void)setNonexistentFilename
{
NSString *filePath = self.filePath;
if ([RZFileManager() fileExistsAtPath:filePath] == NO) {
return;
}
NSString *filenameExtension = self.filename.pathExtension;
NSString *filenameWithoutExtension = self.filename.stringByDeletingPathExtension;
NSUInteger i = 1;
do {
NSString *newFilename = nil;
if (filenameExtension.length == 0) {
newFilename = [NSString stringWithFormat:@"%@_%lu", filenameWithoutExtension, i];
} else {
newFilename = [NSString stringWithFormat:@"%@_%lu.%@", filenameWithoutExtension, i, filenameExtension];
}
filePath = [self.path stringByAppendingPathComponent:newFilename];
i += 1;
} while ([RZFileManager() fileExistsAtPath:filePath]);
self.filename = filePath.lastPathComponent;
}
- (BOOL)openFileHandle
{
NSString *filePath = self.filePath;
if (self.isSender == NO && self.isResume == NO) {
[self setNonexistentFilename];
[RZFileManager() createFileAtPath:filePath contents:[NSData data] attributes:nil];
}
NSFileHandle *fileHandle = [NSFileHandle fileHandleForUpdatingAtPath:filePath];
if (fileHandle == nil) {
[self closeWithLocalizedError:@"TDCFileTransferDialog[nab-dx]"];
return NO;
}
if (self.isResume) {
[fileHandle seekToFileOffset:self.processedFilesize];
}
self.fileHandle = fileHandle;
return YES;
}
- (void)closeFileHandle
{
if (self.fileHandle == nil) {
return;
}
[self.fileHandle closeFile];
self.fileHandle = nil;
}
#pragma mark -
#pragma mark Socket Delegate
- (void)socket:(GCDAsyncSocket *)sock didAcceptNewSocket:(GCDAsyncSocket *)newSocket
{
if (self.isActingAsServer == NO) {
return;
}
if (self.listeningServerConnectedClient == nil) {
self.listeningServerConnectedClient = newSocket;
} else {
[newSocket disconnect];
return;
}
if (self.isReversed) {
self.transferStatus = TDCFileTransferDialogTransferStatusReceiving;
} else {
self.transferStatus = TDCFileTransferDialogTransferStatusSending;
}
[self.transferDialog updateMaintenanceTimer];
if ([self openFileHandle] == NO) {
return;
}
if (self.isReversed) {
[self.readSocket readDataWithTimeout:(-1) tag:0];
} else {
[self send];
}
}
- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port
{
if (self.isActingAsClient == NO) {
return;
}
if (self.isReversed == NO) {
self.transferStatus = TDCFileTransferDialogTransferStatusReceiving;
} else {
self.transferStatus = TDCFileTransferDialogTransferStatusSending;
}
[self.transferDialog updateMaintenanceTimer];
if ([self openFileHandle] == NO) {
return;
}
if (self.isReversed == NO) {
[self.readSocket readDataWithTimeout:(-1) tag:0];
} else {
[self send];
}
}
- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)error
{
if (self.transferStatus == TDCFileTransferDialogTransferStatusComplete ||
self.transferStatus == TDCFileTransferDialogTransferStatusFatalError ||
self.transferStatus == TDCFileTransferDialogTransferStatusRecoverableError)
{
return;
}
if (error) {
[self closeWithLocalizedError:@"TDCFileTransferDialog[s79-3a]" description:error.localizedDescription];
} else {
[self close];
}
}
- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{
if (self.isSender != NO) {
return;
}
/* Update progress */
self.currentRecord += data.length;
self.processedFilesize += data.length;
if (data.length > 0) {
@try {
[self.fileHandle writeData:data];
}
@catch (NSException *exception) {
LogToConsoleError("Caught exception: %{public}@", exception.reason);
LogStackTrace();
if ([exception.reason contains:@"No space left on device"]) {
[self failWithNoSpaceLeftOnDevice];
return;
}
[self closeWithLocalizedError:TXTLS(@"TDCFileTransferDialog[05g-c8]")];
return;
} // @catch
}
/* Send acknowledgement back to server */
uint32_t processedFilesize = (self.processedFilesize & 0xFFFFFFFF);
unsigned char ackPacket[4];
ackPacket[0] = ((processedFilesize >> 24) & 0xFF);
ackPacket[1] = ((processedFilesize >> 16) & 0xFF);
ackPacket[2] = ((processedFilesize >> 8) & 0xFF);
ackPacket[3] = (processedFilesize & 0xFF);
NSData *ackPacketData = [NSData dataWithBytes:ackPacket length:4];
[self.readSocket writeData:ackPacketData withTimeout:(-1) tag:0];
/* Continue requesting data if the transfer is not complete */
if (self.processedFilesize < self.totalFilesize) {
[self.readSocket readDataWithTimeout:(-1) tag:0];
return;
}
/* Update status and tear down transfer */
self.transferStatus = TDCFileTransferDialogTransferStatusComplete;
[self close];
}
#pragma mark -
#pragma mark Socket Write
- (void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag
{
if (self.isSender == NO) {
return;
}
/* Acknowledge sent data */
self.sendQueueSize -= 1;
/* Continue sending data if the transfer is not complete */
if (self.processedFilesize < self.totalFilesize) {
[self send];
return;
}
/* Wait until the send queue has cleared before closing
connection. Just because we finished processing the
data here doesn't mean it has been sent yet. */
if (self.sendQueueSize > 0) {
return;
}
/* Update status and tear down transfer */
self.transferStatus = TDCFileTransferDialogTransferStatusComplete;
[self close];
}
- (void)send
{
if (self.isSender == NO) {
return;
}
if (self.transferStatus != TDCFileTransferDialogTransferStatusSending) {
return;
}
do {
if (self.currentRecord >= RATE_LIMIT) {
return;
}
if (self.sendQueueSize >= MAX_QUEUE_SIZE) {
return;
}
if (self.processedFilesize >= self.totalFilesize) {
return;
}
NSData *dataToWrite = [self.fileHandle readDataOfLength:BUFFER_SIZE];
self.currentRecord += dataToWrite.length;
self.processedFilesize += dataToWrite.length;
self.sendQueueSize += 1;
[self.writeSocket writeData:dataToWrite withTimeout:_sendDataTimeout tag:0];
} while (1);
}
#pragma mark -
#pragma mark Actions
- (void)updateClearButton
{
[self.transferDialog updateClearButton];
}
- (void)reloadStatusInformation
{
TDCFileTransferDialogTableCell *transferTableCell = self.transferTableCell;
if (transferTableCell == nil) {
return;
}
[transferTableCell reloadStatusInformation];
}
#pragma mark -
#pragma mark Properties
- (nullable GCDAsyncSocket *)writeSocket
{
if (self.isReversed) {
return self.connectionToRemoteServer;
} else {
return self.listeningServerConnectedClient;
}
}
- (nullable GCDAsyncSocket *)readSocket
{
if (self.isReversed) {
return self.listeningServerConnectedClient;
} else {
return self.connectionToRemoteServer;
}
}
- (BOOL)isActingAsServer
{
return ((self.isSender && self.isReversed == NO) ||
(self.isSender == NO && self.isReversed));
}
- (BOOL)isActingAsClient
{
return ((self.isSender == NO && self.isReversed == NO) ||
(self.isSender && self.isReversed));
}
- (TDCFileTransferDialog *)transferDialog
{
return [TXSharedApplication sharedFileTransferDialog];
}
- (NSArray *)speedRecords
{
@synchronized (self.speedRecordsPrivate) {
return [self.speedRecordsPrivate copy];
}
}
- (nullable NSString *)filePath
{
NSString *path = self.path;
NSString *filename = self.filename;
if (path == nil || filename == nil) {
return nil;
}
return [path stringByAppendingPathComponent:filename];
}
- (nullable NSURL *)fileURL
{
NSString *filePath = self.filePath;
if (filePath == nil) {
return nil;
}
return [NSURL fileURLWithPath:filePath];
}
- (uint64_t)currentFilesize
{
NSString *filePath = self.filePath;
if (filePath == nil) {
return 0;
}
if ([RZFileManager() fileExistsAtPath:filePath] == NO) {
return 0;
}
NSDictionary *fileAttributes = [RZFileManager() attributesOfItemAtPath:filePath error:NULL];
return fileAttributes.fileSize;
}
- (void)setTransferStatus:(TDCFileTransferDialogTransferStatus)transferStatus
{
if (self->_transferStatus != transferStatus) {
self->_transferStatus = transferStatus;
[self reloadStatusInformation];
}
}
- (void)resetProperties
{
if (self.isResume == NO) {
self.processedFilesize = 0;
}
self.currentRecord = 0;
self.errorMessageDescription = nil;
self.sendQueueSize = 0;
@synchronized(self.speedRecordsPrivate) {
[self.speedRecordsPrivate removeAllObjects];
}
}
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Dialogs/License Manager/Standalone/TDCLicenseManagerDialog.m
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "NSStringHelper.h"
#import "NSViewHelper.h"
#import "TXGlobalModels.h"
#import "TXMasterController.h"
#import "TXMenuController.h"
#import "TPCPreferencesUserDefaults.h"
#import "TDCLicenseManagerMigrateAppStoreSheetPrivate.h"
#import "TDCLicenseManagerRecoverLostLicenseSheetPrivate.h"
#import "TDCLicenseUpgradeActivateSheetPrivate.h"
#import "TDCLicenseUpgradeCommonActionsPrivate.h"
#import "TDCLicenseUpgradeDialogPrivate.h"
#import "TDCLicenseUpgradeEligibilitySheetPrivate.h"
#import "TDCProgressIndicatorSheetPrivate.h"
#import "TLOTimer.h"
#import "TLOLicenseManagerDownloaderPrivate.h"
#import "TLOLicenseManagerLastGenPrivate.h"
#import "TLOLicenseManagerPrivate.h"
#import "TLOLocalization.h"
#import "TLONotificationController.h"
#import "TDCAlert.h"
#import "TDCLicenseManagerDialogPrivate.h"
NS_ASSUME_NONNULL_BEGIN
#if TEXTUAL_BUILT_WITH_LICENSE_MANAGER == 1
NSString * const TDCLicenseManagerActivatedLicenseNotification = @"TDCLicenseManagerActivatedLicenseNotification";
NSString * const TDCLicenseManagerDeactivatedLicenseNotification = @"TDCLicenseManagerDeactivatedLicenseNotification";
NSString * const TDCLicenseManagerTrialExpiredNotification = @"TDCLicenseManagerTrialExpiredNotification";
#define _upgradeDialogRemindMeInterval 345600 // 4 days
@interface TDCLicenseManagerDialog ()
@property (nonatomic, strong) IBOutlet NSView *contentViewUnregisteredTextualView;
@property (nonatomic, strong) IBOutlet NSView *contentViewRegisteredTextualView;
@property (nonatomic, weak) IBOutlet NSTextField *unregisteredViewLicenseKeyTextField;
@property (nonatomic, weak) IBOutlet NSTextField *unregisteredViewTrialInformationTextField;
@property (nonatomic, weak) IBOutlet NSTextField *registeredViewLicenseKeyTextField;
@property (nonatomic, weak) IBOutlet NSTextField *registeredViewLicenseOwnerTextField;
@property (nonatomic, weak) IBOutlet NSTextField *registeredViewLicensePurchaseDateTextField;
@property (nonatomic, weak) IBOutlet NSButton *registeredViewDeactivateTextualButton;
@property (nonatomic, weak) IBOutlet NSButton *unregisteredViewActivateTextualButton;
@property (nonatomic, weak) IBOutlet NSButton *unregisteredViewCancelButton;
@property (nonatomic, weak) IBOutlet NSButton *unregisteredViewRecoveryLostLicenseButton;
@property (nonatomic, weak) IBOutlet NSImageView *unregisteredViewMacAppStoreIconImageView;
@property (nonatomic, strong, nullable) TDCProgressIndicatorSheet *progressIndicator;
@property (nonatomic, strong, nullable) TLOLicenseManagerDownloader *licenseManagerDownloader;
@property (nonatomic, strong, nullable) TDCLicenseManagerMigrateAppStoreSheet *migrateAppStoreSheet;
@property (nonatomic, strong, nullable) TDCLicenseManagerRecoverLostLicenseSheet *recoverLostLicenseSheet;
@property (nonatomic, strong, nullable) TDCLicenseUpgradeDialog *upgradeDialog;
@property (nonatomic, strong, nullable) TDCLicenseUpgradeActivateSheet *upgradeActivateSheet;
@property (nonatomic, assign) BOOL textualIsRegistered;
@property (nonatomic, assign) BOOL isSilentOnSuccess;
@property (nonatomic, assign) BOOL operationInProgress;
@property (nonatomic, strong) TLOTimer *trialTimer;
- (IBAction)unregisteredViewActivateTextual:(id)sender;
- (IBAction)unregisteredViewCancel:(id)sender;
- (IBAction)unregisteredViewMigrateMacAppStorePurchase:(id)sender;
- (IBAction)unregisteredViewPurchaseTextual:(id)sender;
- (IBAction)unregisteredViewRecoveryLostLicense:(id)sender;
- (IBAction)registeredViewDeactivateTextual:(id)sender;
@end
@interface TLONotificationController ()
- (void)scheduleLicenseManagerNotificationWithTitle:(NSString *)title message:(NSString *)message;
@end
@implementation TDCLicenseManagerDialog
#pragma mark -
#pragma mark Dialog Foundation
- (instancetype)init
{
if ((self = [super init])) {
[self prepareInitialState];
return self;
}
return self;
}
- (void)prepareInitialState
{
[RZMainBundle() loadNibNamed:@"TDCLicenseManagerDialog" owner:self topLevelObjects:nil];
[self populateMacAppStoreIconImageView];
[self updateSelectedPane];
}
- (void)show
{
BOOL windowVisible = self.window.visible;
[super show];
if (windowVisible == NO) {
[self.window restoreWindowStateForClass:self.class];
}
}
- (void)applicationDidFinishLaunching
{
[self scheduleTimeRemainingInTrialNotification];
[self toggleTrialTimer];
[self activateLicenseKeyUsingArgumentDictionary];
[self upgradeDialogAppFinishedLaunchingRoutine];
}
- (void)populateMacAppStoreIconImageView
{
/* Read the app store icon image from the actual App Store app so
that we do not have to update it if Apple does. */
NSBundle *appStoreApplication = [NSBundle bundleWithPath:@"/Applications/App Store.app"];
if (appStoreApplication == nil) {
appStoreApplication = [NSBundle bundleWithPath:@"/System/Applications/App Store.app"];
}
if (appStoreApplication == nil) {
return;
}
NSString *appStoreIconPath = [appStoreApplication pathForResource:@"AppIcon" ofType:@"icns"];
if (appStoreIconPath == nil) {
return;
}
NSImage *appStoreIconImage = [[NSImage alloc] initWithContentsOfFile:appStoreIconPath];
self.unregisteredViewMacAppStoreIconImageView.image = appStoreIconImage;
}
- (void)updateSelectedPane
{
NSView *contentView = nil;
self.textualIsRegistered = TLOLicenseManagerTextualIsRegistered();
if (self.textualIsRegistered)
{
NSString *licenseKey = TLOLicenseManagerLicenseKey();
NSString *licenseKeyOwner = TLOLicenseManagerLicenseOwnerName();
NSString *licenseKeyCreationDate = TLOLicenseManagerLicenseCreationDateFormatted();
self.registeredViewLicenseKeyTextField.stringValue = licenseKey;
self.registeredViewLicenseOwnerTextField.stringValue = licenseKeyOwner;
self.registeredViewLicensePurchaseDateTextField.stringValue = licenseKeyCreationDate;
contentView = self.contentViewRegisteredTextualView;
}
else // textualIsRegistered
{
contentView = self.contentViewUnregisteredTextualView;
NSString *formattedTrialInformation = [self timeRemainingInTrialFormattedMessage];
self.unregisteredViewTrialInformationTextField.stringValue = formattedTrialInformation;
}
[self.window replaceContentView:contentView];
}
#pragma mark -
#pragma mark Trial Timer
- (void)toggleTrialTimer
{
if (TLOLicenseManagerTextualIsRegistered()) {
[self stopTrialTimer];
} else {
[self startTrialTimer];
}
}
- (void)startTrialTimer
{
if (self.trialTimer != nil) {
return;
}
NSTimeInterval timeRemaining = (TLOLicenseManagerTimeRemainingTrial() * (-1.0));
if (timeRemaining == 0) {
return;
}
TLOTimer *trialTimer = [TLOTimer timerWithActionBlock:^(TLOTimer *sender) {
[self onTrialTimer];
}];
self.trialTimer = trialTimer;
[trialTimer start:timeRemaining];
}
- (void)stopTrialTimer
{
if (self.trialTimer == nil) {
return;
}
[self.trialTimer stop];
self.trialTimer = nil;
}
- (void)onTrialTimer
{
[self stopTrialTimer];
[RZNotificationCenter() postNotificationName:TDCLicenseManagerTrialExpiredNotification object:self];
}
#pragma mark -
#pragma mark Activate License
- (void)unregisteredViewPurchaseTextual:(id)sender
{
NSString *lastGenLicenseKey = [TLOLicenseManagerLastGen licenseKey];
if (lastGenLicenseKey != nil) {
BOOL upgradeLicense =
[TDCAlert modalAlertWithMessage:TXTLS(@"TLOLicenseManager[dpo-ln]", lastGenLicenseKey.prettyLicenseKey)
title:TXTLS(@"TLOLicenseManager[12h-3w]")
defaultButton:TXTLS(@"TLOLicenseManager[qrx-aq]")
alternateButton:TXTLS(@"TLOLicenseManager[zp8-8q]")];
if (upgradeLicense) {
[self showUpgradeDialogForLicenseKey:lastGenLicenseKey];
return;
}
}
[menuController() openStandaloneStoreWebpage:nil];
}
- (void)unregisteredViewCancel:(id)sender
{
[self close];
}
- (void)updateUnregisteredViewActivationButton
{
if (self.textualIsRegistered) {
return; // Cancel operation...
}
NSString *licenseKeyValue = self.unregisteredViewLicenseKeyTextField.stringValue.trim;
if (TLOLicenseManagerLicenseKeyIsValid(licenseKeyValue)) {
self.unregisteredViewActivateTextualButton.enabled = YES;
} else {
self.unregisteredViewActivateTextualButton.enabled = NO;
}
}
- (void)unregisteredViewActivateTextual:(id)sender
{
NSString *licenseKeyValue = self.unregisteredViewLicenseKeyTextField.stringValue;
[self attemptToActivateLicenseKey:licenseKeyValue];
}
- (void)activateLicenseKeyUsingArgumentDictionary
{
if (TLOLicenseManagerTextualIsRegistered()) {
return; // Nothing to do here...
}
NSDictionary *commandLineArguments = [[NSUserDefaults standardUserDefaults] volatileDomainForName:NSArgumentDomain];
NSString *argumentLicenseKey = commandLineArguments[@"-licenseKey"];
if (argumentLicenseKey == nil) {
return;
}
[self activateLicenseKey:argumentLicenseKey silently:YES];
}
- (void)activateLicenseKey:(NSString *)licenseKey
{
NSParameterAssert(licenseKey != nil);
[self activateLicenseKey:licenseKey silently:NO];
}
- (void)activateLicenseKey:(NSString *)licenseKey silently:(BOOL)silently
{
NSParameterAssert(licenseKey != nil);
/* This method is allowed to be invoked by another class in order
to activate a license. It is not invoked by this class on its own. */
if (TLOLicenseManagerLicenseKeyIsValid(licenseKey)) {
[self attemptToActivateLicenseKey:licenseKey silently:silently];
}
}
- (void)attemptToActivateLicenseKey:(NSString *)licenseKey
{
NSParameterAssert(licenseKey != nil);
[self attemptToActivateLicenseKey:licenseKey silently:NO];
}
- (void)attemptToActivateLicenseKey:(NSString *)licenseKey silently:(BOOL)silently
{
NSParameterAssert(licenseKey != nil);
/* User can click a link or do something else while an activation is already in
progress, so we try to recognize when that happens so that we can prevent
confusion when an operation is already in progress. */
/* This is the only place in the dialog where user can perform an action by
outside influence. Everything else is internalized which means this check is
only necessary here... at least for now. */
if (self.operationInProgress) {
[TDCAlert modalAlertWithMessage:TXTLS(@"TLOLicenseManager[vnu-5e]")
title:TXTLS(@"TLOLicenseManager[0uc-io]", licenseKey.prettyLicenseKey)
defaultButton:TXTLS(@"Prompts[c7s-dq]")
alternateButton:nil];
return;
}
/* Do not activate license we are already using. */
if (licenseKey == TLOLicenseManagerLicenseKey()) {
[TDCAlert modalAlertWithMessage:TXTLS(@"TLOLicenseManager[fxu-su]")
title:TXTLS(@"TLOLicenseManager[bw3-sc]", licenseKey.prettyLicenseKey)
defaultButton:TXTLS(@"Prompts[c7s-dq]")
alternateButton:nil];
return;
}
/* The activate sheet will close itself when user clicks to make purchase,
but if user activates a license by other means (such as clicking the link
in their e-mail), then we dismiss it here, so that we can do activation. */
[self closeUpgradeActivateSheet];
/* Perform activation */
self.isSilentOnSuccess = silently;
[self beginProgressIndicator];
__weak TDCLicenseManagerDialog *weakSelf = self;
TLOLicenseManagerDownloader *licenseManagerDownloader = [TLOLicenseManagerDownloader new];
licenseManagerDownloader.actionBlock = ^BOOL(NSUInteger statusCode, id _Nullable statusContext) {
return (TLOLicenseManagerWriteLicenseFileContents(statusContext) == TLOLicenseManagerActionResultSuccess);
};
licenseManagerDownloader.errorBlock = ^BOOL(NSUInteger statusCode, id _Nullable statusContext) {
if (statusCode != 0 || statusContext == nil) {
return NO;
}
/* lastGenLicenseKey will only be non-nil if the contents of licenseContents
are for a license that have not been upgraded to Textual 7 yet. */
NSString *lastGenLicenseKey = [TLOLicenseManagerLastGen licenseKeyForLicenseContents:statusContext];
if (lastGenLicenseKey != nil) {
[TDCAlert modalAlertWithMessage:TXTLS(@"TLOLicenseManager[5bu-ov]")
title:TXTLS(@"TLOLicenseManager[pmv-qp]", lastGenLicenseKey.prettyLicenseKey)
defaultButton:TXTLS(@"TLOLicenseManager[53u-lt]")
alternateButton:nil];
[weakSelf showUpgradeDialogForLicenseKey:lastGenLicenseKey];
/* We return YES so no error is displayed except the one above. */
return YES;
}
/* We did not handle the error. */
return NO;
};
licenseManagerDownloader.completionBlock = ^(BOOL operationSuccessful, NSUInteger statusCode, id _Nullable statusContext) {
[weakSelf licenseManagerDownloaderCompletionBlock];
if (operationSuccessful) {
weakSelf.unregisteredViewLicenseKeyTextField.stringValue = @"";
[weakSelf toggleTrialTimer];
[RZNotificationCenter() postNotificationName:TDCLicenseManagerActivatedLicenseNotification object:weakSelf];
/* We close the upgrade dialog if a key is activated because
why would we keep it around under that condition? */
[weakSelf closeUpgradeDialog];
/* Reset context for activate sheet. */
[weakSelf resetUpgradeActivateSheetContext];
}
weakSelf.operationInProgress = NO;
};
self.operationInProgress = YES;
licenseManagerDownloader.isSilentOnSuccess = self.isSilentOnSuccess;
[licenseManagerDownloader activateLicense:licenseKey.trim];
self.licenseManagerDownloader = licenseManagerDownloader;
}
#pragma mark -
#pragma mark License Upgrade Launch Routine
- (void)upgradeDialogAppFinishedLaunchingRoutine
{
/* There is no reason to perform this check if this copy of Textual
is already registered. */
if (TLOLicenseManagerTextualIsRegistered()) {
/* If Textual is registered, then we reset these values because
there is no reason to have them hanging around. */
[self resetUpgradeActivateSheetContext];
return;
}
/* Check if we have license key saved from Textual 6 upgrade dialog. */
if ([self showUpgradeActivateSheet]) {
return;
}
/* Show upgrade dialog */
[self showUpgradeDialogForLastGenLicense];
}
- (void)showUpgradeDialogForLastGenLicense
{
/* Is there even a last generation key? */
NSString *lastGenLicenseKey = [TLOLicenseManagerLastGen licenseKey];
if (lastGenLicenseKey == nil) {
return;
}
/* When was the last time the user was nagged? */
/* Unless user hits "Remind Me Later", then the upgrade dialog is
not hidden due to time limit. This change was made so that if the
user is performing some type of action that causes them to miss the
dialog, such as installing an update, it will show next launch. */
BOOL remindMeLater = [RZUserDefaults() boolForKey:@"Textual 7 Upgrade -> Tv7 -> Remind Me Later"];
NSTimeInterval lastCheckTime = [RZUserDefaults() doubleForKey:@"Textual 7 Upgrade -> Tv7 -> Last Dialog Presentation (LMD)"];
NSTimeInterval currentTime = [[NSDate date] timeIntervalSince1970];
if (lastCheckTime > 0 && remindMeLater) {
if ((currentTime - lastCheckTime) < _upgradeDialogRemindMeInterval) {
LogToConsoleInfo("Not enough time has passed since last presentation");
return;
}
}
[RZUserDefaults() setDouble:currentTime forKey:@"Textual 7 Upgrade -> Tv7 -> Last Dialog Presentation (LMD)"];
[RZUserDefaults() removeObjectForKey:@"Textual 7 Upgrade -> Tv7 -> Remind Me Later"];
/* Nag user */
[self showUpgradeDialogForLicenseKey:lastGenLicenseKey];
}
#pragma mark -
#pragma mark License Upgrade Dialog
- (void)showUpgradeDialogForLicenseKey:(NSString *)licenseKey
{
NSParameterAssert(licenseKey != nil);
if (self.upgradeDialog) {
if ([self.upgradeDialog.licenseKey isEqualToString:licenseKey]) {
[self.upgradeDialog show];
return;
} else {
[self.upgradeDialog close];
}
}
TDCLicenseUpgradeDialog *upgradeDialog =
[[TDCLicenseUpgradeDialog alloc] initWithLicenseKey:licenseKey];
upgradeDialog.delegate = self;
[upgradeDialog show];
self.upgradeDialog = upgradeDialog;
}
- (void)closeUpgradeDialog
{
if (self.upgradeDialog) {
[self.upgradeDialog close];
}
}
- (void)licenseUpgradeDialogEligibilityChanged:(TDCLicenseUpgradeDialog *)sender
{
/* Record eligibility status so that we might present an activate sheet
next time the user opens the app. */
[self setUpgradeActivateSheetContextWithDialog:sender];
}
- (void)licenseUpgradeDialogWRemindMeLater:(TDCLicenseUpgradeDialog *)sender
{
[RZUserDefaults() setBool:YES forKey:@"Textual 7 Upgrade -> Tv7 -> Remind Me Later"];
}
- (void)licenseUpgradeDialogWillClose:(TDCLicenseUpgradeDialog *)sender
{
self.upgradeDialog = nil;
}
#pragma mark -
#pragma mark Upgrade Activate Sheet
- (BOOL)showUpgradeActivateSheet
{
/* Do we have a properly formatted license key? */
NSString *licenseKey = [RZUserDefaults() objectForKey:@"Textual 7 Upgrade -> Tv7 -> Eligible License Key"];
if (licenseKey == nil) {
return NO;
}
if (TLOLicenseManagerLicenseKeyIsValid(licenseKey) == NO) {
return NO;
}
/* Do we have an eligibility that is acceptable? */
NSUInteger eligibility = [RZUserDefaults() unsignedIntegerForKey:@"Textual 7 Upgrade -> Tv7 -> Eligibility"];
if (eligibility != TLOLicenseUpgradeEligibilityDiscount &&
eligibility != TLOLicenseUpgradeEligibilityFree &&
eligibility != TLOLicenseUpgradeEligibilityAlreadyUpgraded)
{
return NO;
}
/* Show ourselves because we will place the sheet on self. */
[self show];
/* Create sheet and start it. */
TDCLicenseUpgradeActivateSheet *activateSheet =
[[TDCLicenseUpgradeActivateSheet alloc] initWithLicenseKey:licenseKey eligibility:eligibility];
activateSheet.delegate = self;
activateSheet.window = self.window;
[activateSheet start];
self.upgradeActivateSheet = activateSheet;
/* Inform launch routine to do nothing more. */
return YES;
}
- (void)closeUpgradeActivateSheet
{
if (self.upgradeActivateSheet) {
[self.upgradeActivateSheet endSheet];
}
}
- (void)setUpgradeActivateSheetContextWithDialog:(TDCLicenseUpgradeDialog *)upgradeDialog
{
NSParameterAssert(upgradeDialog != nil);
[RZUserDefaults() setUnsignedInteger:upgradeDialog.eligibility forKey:@"Textual 7 Upgrade -> Tv7 -> Eligibility"];
[RZUserDefaults() setObject:upgradeDialog.licenseKey forKey:@"Textual 7 Upgrade -> Tv7 -> Eligible License Key"];
}
- (void)resetUpgradeActivateSheetContext
{
/* We reset these values for any successful activation.
It is probably more proper to compare the key activated to the context,
but I don't think it will matter in the real world. */
[RZUserDefaults() removeObjectForKey:@"Textual 7 Upgrade -> Tv7 -> Eligibility"];
[RZUserDefaults() removeObjectForKey:@"Textual 7 Upgrade -> Tv7 -> Eligible License Key"];
}
- (void)upgradeActivateSheetActivateLicense:(TDCLicenseUpgradeActivateSheet *)sender
{
NSString *licenseKey = sender.licenseKey;
[sender endSheet];
[self attemptToActivateLicenseKey:licenseKey];
}
- (void)upgradeActivateSheetPurchaseUpgrade:(TDCLicenseUpgradeActivateSheet *)sender
{
[TDCLicenseUpgradeCommonActions purchaseUpgradeForLicense:sender.licenseKey];
}
- (void)upgradeActivateSheetSuppressed:(TDCLicenseUpgradeActivateSheet *)sender
{
[self resetUpgradeActivateSheetContext];
}
- (void)upgradeActivateSheetWillClose:(TDCLicenseUpgradeActivateSheet *)sender
{
self.upgradeActivateSheet = nil;
}
#pragma mark -
#pragma mark Recover Lost License
- (void)unregisteredViewRecoveryLostLicense:(id)sender
{
TDCLicenseManagerRecoverLostLicenseSheet *recoverLostLicenseSheet =
[[TDCLicenseManagerRecoverLostLicenseSheet alloc] initWithWindow:self.window];
recoverLostLicenseSheet.delegate = self;
[recoverLostLicenseSheet start];
self.recoverLostLicenseSheet = recoverLostLicenseSheet;
}
- (void)licenseManagerRecoverLostLicenseSheet:(TDCLicenseManagerRecoverLostLicenseSheet *)sender onOk:(NSString *)contactAddress
{
__weak TDCLicenseManagerDialog *weakSelf = self;
TLOLicenseManagerDownloader *licenseManagerDownloader = [TLOLicenseManagerDownloader new];
licenseManagerDownloader.completionBlock = ^(BOOL operationSuccessful, NSUInteger statusCode, id _Nullable statusContext) {
[weakSelf licenseManagerDownloaderCompletionBlock];
};
licenseManagerDownloader.isSilentOnSuccess = self.isSilentOnSuccess;
[licenseManagerDownloader requestLostLicenseKeyForContactAddress:contactAddress];
self.licenseManagerDownloader = licenseManagerDownloader;
}
- (void)licenseManagerRecoverLostLicenseSheetWillClose:(TDCLicenseManagerRecoverLostLicenseSheet *)sender
{
self.recoverLostLicenseSheet = nil;
if (self.licenseManagerDownloader) {
[self beginProgressIndicator];
}
}
#pragma mark -
#pragma mark Deactivate License
- (void)registeredViewDeactivateTextual:(id)sender
{
BOOL deactivateCopy = [TDCAlert modalAlertWithMessage:TXTLS(@"TLOLicenseManager[z87-wb]")
title:TXTLS(@"TLOLicenseManager[pg1-a9]")
defaultButton:TXTLS(@"Prompts[mvh-ms]")
alternateButton:TXTLS(@"Prompts[99q-gg]")];
if (deactivateCopy == NO) {
return; // Cancel operation...
}
/* License deactivation does not use a progress indicator because
it does not have to touch the network. It will only delete a file
on the hard drive which is typically instant. */
__weak TDCLicenseManagerDialog *weakSelf = self;
TLOLicenseManagerDownloader *licenseManagerDownloader = [TLOLicenseManagerDownloader new];
licenseManagerDownloader.actionBlock = ^BOOL(NSUInteger statusCode, id _Nullable statusContext) {
return (TLOLicenseManagerDeleteLicenseFile() == TLOLicenseManagerActionResultSuccess);
};
licenseManagerDownloader.completionBlock = ^(BOOL operationSuccessful, NSUInteger statusCode, id _Nullable statusContext) {
[weakSelf licenseManagerDownloaderCompletionBlock];
[weakSelf toggleTrialTimer];
[RZNotificationCenter() postNotificationName:TDCLicenseManagerDeactivatedLicenseNotification object:weakSelf];
};
licenseManagerDownloader.isSilentOnSuccess = self.isSilentOnSuccess;
[licenseManagerDownloader deactivateLicense];
// self.licenseManagerDownloader = licenseManagerDownloader;
}
#pragma mark -
#pragma mark Mac App Store Receipt Processing
- (void)unregisteredViewMigrateMacAppStorePurchase:(id)sender
{
TDCLicenseManagerMigrateAppStoreSheet *migrateAppStoreSheet =
[[TDCLicenseManagerMigrateAppStoreSheet alloc] initWithWindow:self.window];
migrateAppStoreSheet.delegate = self;
[migrateAppStoreSheet start];
self.migrateAppStoreSheet = migrateAppStoreSheet;
}
- (void)licenseManagerMigrateAppStoreSheet:(TDCLicenseManagerMigrateAppStoreSheet *)sender
convertReceipt:(NSString *)receiptData
licenseOwnerName:(NSString *)licenseOwnerName
licenseOwnerContactAddress:(NSString *)licenseOwnerContactAddress
{
__weak TDCLicenseManagerDialog *weakSelf = self;
TLOLicenseManagerDownloader *licenseManagerDownloader = [TLOLicenseManagerDownloader new];
licenseManagerDownloader.completionBlock = ^(BOOL operationSuccessful, NSUInteger statusCode, id _Nullable statusContext) {
[weakSelf licenseManagerDownloaderCompletionBlock];
};
licenseManagerDownloader.isSilentOnSuccess = self.isSilentOnSuccess;
[licenseManagerDownloader migrateMacAppStorePurchase:receiptData
licenseOwnerName:licenseOwnerName
licenseOwnerContactAddress:licenseOwnerContactAddress];
self.licenseManagerDownloader = licenseManagerDownloader;
}
- (void)licenseManagerMigrateAppStoreSheetWillClose:(TDCLicenseManagerMigrateAppStoreSheet *)sender
{
self.migrateAppStoreSheet = nil;
if (self.licenseManagerDownloader) {
[self beginProgressIndicator];
}
}
#pragma mark -
#pragma mark NSTextField Delegate
- (void)controlTextDidChange:(NSNotification *)obj
{
if (obj.object == self.unregisteredViewLicenseKeyTextField) {
[self updateUnregisteredViewActivationButton];
}
}
#pragma mark -
#pragma mark Helper Methods
- (void)licenseManagerDownloaderCompletionBlock
{
self.licenseManagerDownloader = nil;
[self endProgressIndicator];
[self updateSelectedPane];
[self updateUnregisteredViewActivationButton];
self.isSilentOnSuccess = NO; // Reset flag regardless of state.
// This flag is one-time use.
}
- (void)beginProgressIndicator
{
self.progressIndicator = [[TDCProgressIndicatorSheet alloc] initWithWindow:self.window];
[self.progressIndicator start];
}
- (void)endProgressIndicator
{
if (self.progressIndicator == nil) {
return;
}
[self.progressIndicator stop];
self.progressIndicator = nil;
}
#pragma mark -
#pragma mark Notification Center
- (NSString *)timeRemainingInTrialFormattedMessage
{
NSTimeInterval timeLeft = TLOLicenseManagerTimeRemainingTrial();
if (timeLeft >= 0) {
return TXTLS(@"TLOLicenseManager[kn7-ju]");
}
NSString *formattedTimeRemainingString = TXHumanReadableTimeInterval(timeLeft, YES, NSCalendarUnitDay);
return TXTLS(@"TLOLicenseManager[wdl-3f]", formattedTimeRemainingString);
}
- (void)scheduleTimeRemainingInTrialNotification
{
if (TLOLicenseManagerTextualIsRegistered() || TLOLicenseManagerIsTrialExpired()) {
return; // Do not schedule notification...
}
NSString *title = [self timeRemainingInTrialFormattedMessage];
NSString *message = TXTLS(@"TLOLicenseManager[ccj-ag]");
[sharedNotificationController() scheduleLicenseManagerNotificationWithTitle:title message:message];
}
#pragma mark -
#pragma mark Window Delegate
- (void)windowWillClose:(NSNotification *)note
{
[self.window saveWindowStateForClass:self.class];
}
@end
#endif
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Dialogs/License Manager/Standalone/TDCLicenseManagerMigrateAppStoreSheet.m
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import
#import "TPCPathInfo.h"
#import "TLOLocalization.h"
#import "TVCValidatedTextField.h"
#import "TDCLicenseManagerMigrateAppStoreSheetPrivate.h"
NS_ASSUME_NONNULL_BEGIN
/*
* TDCLicenseManagerMigrateAppStoreSheet presents an open dialog to
* find a copy of Textual with a receipt then presents a sheet asking
* for the user's e-mail address as long as a valid receipt is present.
*/
#if TEXTUAL_BUILT_WITH_LICENSE_MANAGER == 1
#define _licenseOwnerNameMaximumLength 255
#define _licenseOwnerContactAddressMaximumLength 2000
@interface TDCLicenseManagerMigrateAppStoreSheet ()
@property (nonatomic, weak) IBOutlet TVCValidatedTextField *licenseOwnerNameTextField;
@property (nonatomic, weak) IBOutlet TVCValidatedTextField *licenseOwnerContactAddressTextField;
@property (nonatomic, copy) NSString *cachedReceiptData;
@end
@implementation TDCLicenseManagerMigrateAppStoreSheet
#pragma mark -
#pragma mark Contact Address Sheet
- (instancetype)initWithWindow:(nullable NSWindow *)window
{
if ((self = [super initWithWindow:window])) {
[self prepareInitialState];
return self;
}
return nil;
}
- (void)prepareInitialState
{
[RZMainBundle() loadNibNamed:@"TDCLicenseManagerMigrateAppStoreSheet" owner:self topLevelObjects:nil];
}
- (void)startContactAddressSheet
{
/* E-mail address text field configuration */
self.licenseOwnerContactAddressTextField.stringValueIsInvalidOnEmpty = YES;
self.licenseOwnerContactAddressTextField.stringValueUsesOnlyFirstToken = YES;
self.licenseOwnerContactAddressTextField.textDidChangeCallback = self;
self.licenseOwnerContactAddressTextField.stringValue = [XRAddressBook myEmailAddress];
self.licenseOwnerContactAddressTextField.validationBlock = ^NSString *(NSString *currentValue) {
if ([currentValue containsCharactersFromCharacterSet:[NSCharacterSet newlineCharacterSet]]) {
return TXTLS(@"CommonErrors[gas-v8]");
}
if (currentValue.length > _licenseOwnerContactAddressMaximumLength) {
return TXTLS(@"CommonErrors[2cb-af]", _licenseOwnerContactAddressMaximumLength);
}
return nil;
};
/* First & last name text field configuration */
self.licenseOwnerNameTextField.stringValueIsInvalidOnEmpty = YES;
self.licenseOwnerNameTextField.stringValueUsesOnlyFirstToken = NO;
self.licenseOwnerNameTextField.textDidChangeCallback = self;
self.licenseOwnerNameTextField.stringValue = [XRAddressBook myName];
self.licenseOwnerNameTextField.validationBlock = ^NSString *(NSString *currentValue) {
if ([currentValue containsCharactersFromCharacterSet:[NSCharacterSet newlineCharacterSet]]) {
return TXTLS(@"CommonErrors[gas-v8]");
}
if (currentValue.length > _licenseOwnerNameMaximumLength) {
return TXTLS(@"CommonErrors[2cb-af]", _licenseOwnerNameMaximumLength);
}
return nil;
};
/* Begin sheet... */
[self startSheet];
}
- (void)start
{
[self findTextualUsingLaunchServices];
}
- (void)ok:(id)sender
{
if ([self okOrError] == NO) {
return;
}
NSString *receiptData = self.cachedReceiptData;
NSString *licenseOwnerName = self.licenseOwnerNameTextField.value;
NSString *licenseOwnerContactAddress = self.licenseOwnerContactAddressTextField.value;
[self.delegate licenseManagerMigrateAppStoreSheet:self
convertReceipt:receiptData
licenseOwnerName:licenseOwnerName
licenseOwnerContactAddress:licenseOwnerContactAddress];
[super ok:sender];
}
- (BOOL)okOrError
{
if ([self okOrErrorForTextField:self.licenseOwnerNameTextField] == NO) {
return NO;
}
if ([self okOrErrorForTextField:self.licenseOwnerContactAddressTextField] == NO) {
return NO;
}
return YES;
}
#pragma mark -
#pragma mark Open Dialog
- (BOOL)panel:(id)sender validateURL:(NSURL *)url error:(NSError **)outError
{
NSString *applicationName = nil;
if ([self canUseApplicationAtURL:url applicationName:&applicationName] == NO) {
if (outError) {
NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
userInfo[NSURLErrorKey] = url;
userInfo[NSLocalizedDescriptionKey] = TXTLS(@"TLOLicenseManager[b6l-ka]", applicationName);
userInfo[NSLocalizedRecoverySuggestionErrorKey] = TXTLS(@"TLOLicenseManager[sdj-xd]");
*outError = [NSError errorWithDomain:TXErrorDomain code:27984 userInfo:userInfo];
}
return NO;
}
return YES;
}
- (void)findTextualUsingLaunchServices
{
CFURLRef searchScopeURL = (__bridge CFURLRef)[NSURL URLWithString:@"textual://knowledge-base"];
NSArray *matchedApplications = (__bridge_transfer NSArray *)LSCopyApplicationURLsForURL(searchScopeURL, kLSRolesViewer);
NSURL *matchedApplication = nil;
for (NSURL *applicationURL in matchedApplications) {
if ([self canUseApplicationAtURL:applicationURL applicationName:NULL]) {
matchedApplication = applicationURL;
LogToConsoleInfo("Automatically detected Mac App Store Textual 7 at the following path: %{public}@",
matchedApplication.standardizedTildePath);
break;
}
}
if (matchedApplication) {
[self haveApplicationAtURL:matchedApplication];
} else {
[self presentOpenDialog];
}
}
- (void)presentOpenDialog
{
NSOpenPanel *d = [NSOpenPanel openPanel];
NSURL *applicationsPath = [TPCPathInfo systemApplicationsURL];
if (applicationsPath) {
d.directoryURL = applicationsPath;
}
d.allowedFileTypes = @[@"app"];
d.delegate = (id)self;
d.allowsMultipleSelection = NO;
d.canChooseDirectories = NO;
d.canChooseFiles = YES;
d.canCreateDirectories = NO;
d.resolvesAliases = YES;
d.message = TXTLS(@"TLOLicenseManager[vft-qo]");
d.prompt = TXTLS(@"Prompts[xne-79]");
[d beginSheetModalForWindow:self.window completionHandler:^(NSInteger result) {
if (result == NSModalResponseOK) {
[self haveApplicationAtURL:d.URL];
} else {
[self cancel:nil];
}
}];
}
- (void)haveApplicationAtURL:(NSURL *)applicationURL
{
NSParameterAssert(applicationURL != nil);
NSString *receiptData = [self receiptDataForApplicationAtURL:applicationURL];
if (receiptData) {
self.cachedReceiptData = receiptData;
XRPerformBlockAsynchronouslyOnMainQueue(^{
[self startContactAddressSheet];
});
return;
}
[self cancel:nil];
}
#pragma mark -
#pragma mark Helper Methods
- (nullable NSString *)receiptDataForApplicationAtURL:(NSURL *)applicationURL
{
NSParameterAssert(applicationURL != nil);
/* Locate application bundle and determine whether the receipt
file is even contained within it. */
NSBundle *applicationBundle = [NSBundle bundleWithURL:applicationURL];
if (applicationBundle == nil) {
return nil;
}
NSURL *receiptFileURL = applicationBundle.appStoreReceiptURL;
if (receiptFileURL == nil) {
return nil;
}
if ([RZFileManager() fileExistsAtURL:receiptFileURL] == NO) {
return nil;
}
/* If the receipt file exists, request the data and cache the base64
value of the receipt data. */
NSError *receiptDataReadError = nil;
NSData *receiptData = [NSData dataWithContentsOfURL:receiptFileURL options:0 error:&receiptDataReadError];
if (receiptData == nil) {
LogToConsoleError("Failed to read the contents of the receipt file '%{public}@': %{public}@",
receiptFileURL.standardizedTildePath, receiptDataReadError.localizedDescription);
return nil;
}
return [XRBase64Encoding encodeData:receiptData];
}
- (BOOL)canUseApplicationAtURL:(NSURL *)applicationURL applicationName:(NSString * _Nullable * _Nullable)applicationName
{
/* The license API performs validation of the uploaded receipt which
means that the the only thing we need to know at this point is that
the bundle identifier of the application is a known value and that
the receipt file actually does exist in the application. */
NSBundle *applicationBundle = [NSBundle bundleWithURL:applicationURL];
if (applicationBundle == nil) {
return NO;
}
/* Pass to caller the application name of the bundle. */
if ( applicationName) {
*applicationName = applicationBundle.displayName;
}
/* Compare bundle identifier. */
/* The bundle identifier used for comparison is hard coded is because
the bundle identifier for the running copy can be different than the
value that we are expecting from an older copy which we cannot change. */
NSString *applicationBundleID = [applicationBundle objectForInfoDictionaryKey:@"CFBundleIdentifier"];
if (applicationBundleID == nil ||
([applicationBundleID isEqualToString:@"com.codeux.irc.textual5"] == NO &&
[applicationBundleID isEqualToString:@"com.codeux.apps.textual-mas"] == NO))
{
return NO;
}
/* Determine whether a receipt file exists. */
NSURL *receiptFileURL = applicationBundle.appStoreReceiptURL;
if (receiptFileURL == nil) {
return NO;
}
if ([RZFileManager() fileExistsAtURL:receiptFileURL] == NO) {
return NO;
}
/* Return successful result */
return YES;
}
#pragma mark -
#pragma mark NSWindow Delegate
- (void)windowWillClose:(NSNotification *)note
{
[self.delegate licenseManagerMigrateAppStoreSheetWillClose:self];
}
@end
#endif
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Dialogs/License Manager/Standalone/TDCLicenseManagerRecoverLostLicenseSheet.m
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "TLOLocalization.h"
#import "TVCValidatedTextField.h"
#import "TDCLicenseManagerRecoverLostLicenseSheetPrivate.h"
NS_ASSUME_NONNULL_BEGIN
#if TEXTUAL_BUILT_WITH_LICENSE_MANAGER == 1
#define _licenseOwnerContactAddressMaximumLength 2000
@interface TDCLicenseManagerRecoverLostLicenseSheet ()
@property (nonatomic, weak) IBOutlet TVCValidatedTextField *contactAddressTextField;
@end
@implementation TDCLicenseManagerRecoverLostLicenseSheet
- (instancetype)initWithWindow:(nullable NSWindow *)window
{
if ((self = [super initWithWindow:window])) {
[self prepareInitialState];
return self;
}
return nil;
}
- (void)prepareInitialState
{
[RZMainBundle() loadNibNamed:@"TDCLicenseManagerRecoverLostLicenseSheet" owner:self topLevelObjects:nil];
}
- (void)start
{
self.contactAddressTextField.stringValueIsInvalidOnEmpty = YES;
self.contactAddressTextField.stringValueUsesOnlyFirstToken = YES;
self.contactAddressTextField.textDidChangeCallback = self;
self.contactAddressTextField.stringValue = [XRAddressBook myEmailAddress];
self.contactAddressTextField.validationBlock = ^NSString *(NSString *currentValue) {
if ([currentValue containsCharactersFromCharacterSet:[NSCharacterSet newlineCharacterSet]]) {
return TXTLS(@"CommonErrors[gas-v8]");
}
if (currentValue.length > _licenseOwnerContactAddressMaximumLength) {
return TXTLS(@"CommonErrors[2cb-af]", _licenseOwnerContactAddressMaximumLength);
}
return nil;
};
[self startSheet];
}
- (void)ok:(id)sender
{
if ([self okOrError] == NO) {
return;
}
NSString *contactAddress = self.contactAddressTextField.value;
[self.delegate licenseManagerRecoverLostLicenseSheet:self onOk:contactAddress];
[super ok:sender];
}
- (BOOL)okOrError
{
return [self okOrErrorForTextField:self.contactAddressTextField];
}
#pragma mark -
#pragma mark NSWindow Delegate
- (void)windowWillClose:(NSNotification *)note
{
[self.delegate licenseManagerRecoverLostLicenseSheetWillClose:self];
}
@end
#endif
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Dialogs/License Manager/Standalone/TDCLicenseUpgradeActivateSheet.m
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "NSObjectHelperPrivate.h"
#import "NSStringHelper.h"
#import "TDCLicenseUpgradeActivateSheetPrivate.h"
NS_ASSUME_NONNULL_BEGIN
#if TEXTUAL_BUILT_WITH_LICENSE_MANAGER == 1
@interface TDCLicenseUpgradeActivateSheet ()
@property (nonatomic, copy, readwrite) NSString *licenseKey;
@property (nonatomic, assign, readwrite) TLOLicenseUpgradeEligibility eligibility;
@property (nonatomic, strong) IBOutlet NSWindow *sheetEligibleDiscount;
@property (nonatomic, strong) IBOutlet NSWindow *sheetEligibleFree;
@property (nonatomic, weak) IBOutlet NSTextField *sheetEligibleDiscountTitleTextField;
@property (nonatomic, weak) IBOutlet NSTextField *sheetEligibleFreeTitleTextField;
@property (nonatomic, weak) IBOutlet NSButton *sheetEligibleDiscountSuppressionButton;
@property (nonatomic, weak) IBOutlet NSButton *sheetEligibleFreeSuppressionButton;
- (IBAction)actionActivateLicense:(id)sender;
- (IBAction)actionPurchaseUpgrade:(id)sender;
- (IBAction)actionCancel:(id)sender;
@end
@implementation TDCLicenseUpgradeActivateSheet
#pragma mark -
#pragma mark Dialog Foundation
- (instancetype)initWithLicenseKey:(NSString *)licenseKey eligibility:(TLOLicenseUpgradeEligibility)eligibility
{
NSParameterAssert(licenseKey != nil);
if ((self = [super initWithWindow:nil])) {
self.licenseKey = licenseKey;
self.eligibility = eligibility;
[self prepareInitialState];
return self;
}
return self;
}
- (void)prepareInitialState
{
[RZMainBundle() loadNibNamed:@"TDCLicenseUpgradeActivateSheet" owner:self topLevelObjects:nil];
}
- (void)start
{
[self startSheet];
}
- (void)startSheet
{
NSTextField *sheetTitleTextField = nil;
if (self.eligibility == TLOLicenseUpgradeEligibilityDiscount)
{
self.sheet = self.sheetEligibleDiscount;
sheetTitleTextField = self.sheetEligibleDiscountTitleTextField;
}
else if (self.eligibility == TLOLicenseUpgradeEligibilityFree ||
self.eligibility == TLOLicenseUpgradeEligibilityAlreadyUpgraded)
{
self.sheet = self.sheetEligibleFree;
sheetTitleTextField = self.sheetEligibleFreeTitleTextField;
}
else
{
NSAssert(NO, @"Cannot display a sheet for this type of eligibility");
}
sheetTitleTextField.stringValue =
[NSString stringWithFormat:
sheetTitleTextField.stringValue, self.licenseKey.prettyLicenseKey];
[super startSheet];
}
- (void)actionActivateLicense:(id)sender
{
[self.delegate upgradeActivateSheetActivateLicense:self];
}
- (void)actionPurchaseUpgrade:(id)sender
{
[self.delegate upgradeActivateSheetPurchaseUpgrade:self];
}
- (void)actionCancel:(id)sender
{
/* Only one of two sheets can ever be visible so just check if one is on. */
if (self.sheetEligibleDiscountSuppressionButton.state == NSControlStateValueOn ||
self.sheetEligibleFreeSuppressionButton.state == NSControlStateValueOn)
{
[self.delegate upgradeActivateSheetSuppressed:self];
}
[self endSheet];
}
#pragma mark -
#pragma mark NSWindow Delegate
- (void)windowWillClose:(NSNotification *)note
{
[self.delegate upgradeActivateSheetWillClose:self];
}
@end
#endif
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Dialogs/License Manager/Standalone/TDCLicenseUpgradeCommonActions.m
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "TXMasterController.h"
#import "TXMenuControllerPrivate.h"
#import "TLOpenLink.h"
#import "TDCLicenseUpgradeCommonActionsPrivate.h"
NS_ASSUME_NONNULL_BEGIN
#if TEXTUAL_BUILT_WITH_LICENSE_MANAGER == 1
@implementation TDCLicenseUpgradeCommonActions
+ (void)contactSupport
{
[menuController() contactSupport:nil];
}
+ (void)activateLicense:(NSString *)licenseKey
{
NSParameterAssert(licenseKey != nil);
[menuController() manageLicense:nil activateLicenseKey:licenseKey];
}
+ (void)purchaseUpgradeForLicense:(NSString *)licenseKey
{
NSParameterAssert(licenseKey != nil);
NSString *linkToOpen = [NSString stringWithFormat:@"https://www.codeux.com/textual/version-7-upgrade/upgradeLicense/%@", licenseKey];
[TLOpenLink openWithString:linkToOpen inBackground:NO];
}
+ (void)learnMore
{
NSURL *urlToOpen = [NSURL URLWithString:@"https://www.codeux.com/textual/version-7-upgrade/learnMore"];
[TLOpenLink open:urlToOpen inBackground:NO];
}
+ (void)openStandaloneStore
{
[menuController() openStandaloneStoreWebpage:nil];
}
@end
#endif
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Dialogs/License Manager/Standalone/TDCLicenseUpgradeDialog.m
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "NSObjectHelperPrivate.h"
#import "TLOLicenseManagerPrivate.h"
#import "TDCLicenseManagerDialogPrivate.h"
#import "TDCLicenseUpgradeCommonActionsPrivate.h"
#import "TDCLicenseUpgradeDialogPrivate.h"
NS_ASSUME_NONNULL_BEGIN
#if TEXTUAL_BUILT_WITH_LICENSE_MANAGER == 1
@interface TDCLicenseUpgradeDialog ()
@property (nonatomic, copy, readwrite) NSString *licenseKey;
@property (nonatomic, assign, readwrite) TLOLicenseUpgradeEligibility eligibility;
@property (nonatomic, strong, nullable) TDCLicenseUpgradeEligibilitySheet *EligibilitySheet;
@property (nonatomic, weak) IBOutlet NSButton *upgradeDialogContinueTrialButton;
@property (nonatomic, weak) IBOutlet NSTextField *upgradeDialogTrialPeriodTextField;
- (IBAction)actionLearnMore:(id)sender;
- (IBAction)actionPurchaseUpgrade:(id)sender;
- (IBAction)actionContinueTrial:(id)sender;
- (IBAction)actionRemindMeLater:(id)sender;
@end
@implementation TDCLicenseUpgradeDialog
#pragma mark -
#pragma mark Dialog Foundation
- (instancetype)init
{
[self doesNotRecognizeSelector:_cmd];
return nil;
}
- (instancetype)initWithLicenseKey:(NSString *)licenseKey
{
NSParameterAssert(licenseKey != nil);
if ((self = [super init])) {
self.licenseKey = licenseKey;
[self prepareInitialState];
return self;
}
return self;
}
- (void)prepareInitialState
{
[RZMainBundle() loadNibNamed:@"TDCLicenseUpgradeDialog" owner:self topLevelObjects:nil];
self.eligibility = TLOLicenseUpgradeEligibilityUnknown;
}
- (void)show
{
self.upgradeDialogContinueTrialButton.enabled = (TLOLicenseManagerIsTrialExpired() == NO);
self.upgradeDialogTrialPeriodTextField.stringValue = [[TXSharedApplication sharedLicenseManagerDialog] timeRemainingInTrialFormattedMessage];
[super show];
}
#pragma mark -
#pragma mark Eligibility Sheet Actions
- (void)checkEligibility
{
if (self.EligibilitySheet != nil) {
return;
}
TDCLicenseUpgradeEligibilitySheet *eligibilitySheet =
[[TDCLicenseUpgradeEligibilitySheet alloc] initWithLicenseKey:self.licenseKey];
eligibilitySheet.delegate = self;
eligibilitySheet.window = self.window;
[eligibilitySheet checkEligibility];
self.EligibilitySheet = eligibilitySheet;
}
- (void)closeEligibilitySheet
{
if (self.EligibilitySheet) {
[self.EligibilitySheet endSheet];
}
}
- (void)upgradeEligibilitySheetContactSupport:(TDCLicenseUpgradeEligibilitySheet *)sender
{
[TDCLicenseUpgradeCommonActions contactSupport];
}
- (void)upgradeEligibilitySheetActivateLicense:(TDCLicenseUpgradeEligibilitySheet *)sender
{
[TDCLicenseUpgradeCommonActions activateLicense:sender.licenseKey];
}
- (void)upgradeEligibilitySheetPurchaseUpgrade:(TDCLicenseUpgradeEligibilitySheet *)sender
{
[TDCLicenseUpgradeCommonActions purchaseUpgradeForLicense:sender.licenseKey];
}
- (void)upgradeEligibilitySheetPurchaseStandalone:(TDCLicenseUpgradeEligibilitySheet *)sender
{
[TDCLicenseUpgradeCommonActions openStandaloneStore];
}
- (void)upgradeEligibilitySheetChanged:(TDCLicenseUpgradeEligibilitySheet *)sender
{
self.eligibility = sender.eligibility;
[self.delegate licenseUpgradeDialogEligibilityChanged:self];
}
- (void)upgradeEligibilitySheetWillClose:(TDCLicenseUpgradeEligibilitySheet *)sender
{
self.EligibilitySheet = nil;
}
#pragma mark -
#pragma mark Upgrade Dialog Actions
- (void)actionLearnMore:(id)sender
{
[TDCLicenseUpgradeCommonActions learnMore];
}
- (void)actionPurchaseUpgrade:(id)sender
{
[self checkEligibility];
}
- (void)actionContinueTrial:(id)sender
{
[self.delegate licenseUpgradeDialogWRemindMeLater:self];
[self close];
}
- (void)actionRemindMeLater:(id)sender
{
[self.delegate licenseUpgradeDialogWRemindMeLater:self];
[self close];
}
#pragma mark -
#pragma mark NSWindow Delegate
- (void)windowWillClose:(NSNotification *)note
{
[self closeEligibilitySheet];
[self.delegate licenseUpgradeDialogWillClose:self];
}
@end
#endif
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Dialogs/License Manager/Standalone/TDCLicenseUpgradeEligibilitySheet.m
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "NSObjectHelperPrivate.h"
#import "NSStringHelper.h"
#import "TXGlobalModels.h"
#import "TLOLocalization.h"
#import "TLOLicenseManagerPrivate.h"
#import "TLOLicenseManagerDownloaderPrivate.h"
#import "TDCAlert.h"
#import "TDCProgressIndicatorSheetPrivate.h"
#import "TDCLicenseUpgradeEligibilitySheetPrivate.h"
NS_ASSUME_NONNULL_BEGIN
#if TEXTUAL_BUILT_WITH_LICENSE_MANAGER == 1
@interface TDCLicenseUpgradeEligibilitySheet ()
@property (nonatomic, copy, readwrite) NSString *licenseKey;
@property (nonatomic, assign, readwrite) TLOLicenseUpgradeEligibility eligibility;
@property (nonatomic, strong) TLOLicenseManagerDownloader *licenseManagerDownloader;
@property (nonatomic, strong) TDCProgressIndicatorSheet *progressIndicator;
@property (nonatomic, strong) IBOutlet NSWindow *sheetNotEligible;
@property (nonatomic, strong) IBOutlet NSWindow *sheetEligibleDiscount;
@property (nonatomic, strong) IBOutlet NSWindow *sheetEligibleFree;
@property (nonatomic, assign) BOOL checkingEligibility;
- (IBAction)actionContactSupport:(id)sender;
- (IBAction)actionActivateLicense:(id)sender;
- (IBAction)actionPurchaseUpgrade:(id)sender;
- (IBAction)actionPurchaseStandalone:(id)sender;
- (IBAction)actionClose:(id)sender;
@end
@implementation TDCLicenseUpgradeEligibilitySheet
#pragma mark -
#pragma mark Dialog Foundation
- (instancetype)initWithLicenseKey:(NSString *)licenseKey
{
NSParameterAssert(licenseKey != nil);
if ((self = [super initWithWindow:nil])) {
self.licenseKey = licenseKey;
[self prepareInitialState];
return self;
}
return self;
}
- (void)prepareInitialState
{
[RZMainBundle() loadNibNamed:@"TDCLicenseUpgradeEligibilitySheet" owner:self topLevelObjects:nil];
self.eligibility = TLOLicenseUpgradeEligibilityUnknown;
}
- (void)startSheet
{
LogToConsoleError("This method does nothing. Use -checkEligibility instead");
LogStackTrace();
}
- (void)endSheet
{
[self _cancelEligibilityCheck];
[super endSheet];
}
- (void)endSheetEarly
{
/* If we end sheet early, before self.sheet is ever defined,
then trying to close it wont fire this delegate call.
We fake the call to the delegate so that the sheet can be released. */
[self windowWillClose:nil];
}
- (void)checkEligibility
{
[self _checkEligibility];
}
#pragma mark -
#pragma mark Utilities
- (void)_beginProgressIndicator
{
[self _beginProgressIndicatorInWindow:self.window];
}
- (void)_beginProgressIndicatorInWindow:(NSWindow *)window
{
self.progressIndicator = [[TDCProgressIndicatorSheet alloc] initWithWindow:window];
[self.progressIndicator start];
}
- (void)_endProgressIndicator
{
if (self.progressIndicator == nil) {
return;
}
[self.progressIndicator stop];
self.progressIndicator = nil;
}
#pragma mark -
#pragma mark Eligibility Sheet Actions
- (void)_presentEligibilityCheckFailedSheetWithError:(NSString *)errorMessage
{
NSParameterAssert(errorMessage != nil);
[TDCAlert alertSheetWithWindow:self.window
body:TXTLS(@"TDCLicenseUpgradeEligibilitySheet[8hb-y3]", errorMessage)
title:TXTLS(@"TDCLicenseUpgradeEligibilitySheet[wmk-xg]", self.licenseKey.prettyLicenseKey)
defaultButton:TXTLS(@"Prompts[c7s-dq]")
alternateButton:TXTLS(@"TDCLicenseUpgradeEligibilitySheet[dn3-4r]")
otherButton:nil
completionBlock:^(TDCAlertResponse buttonClicked, BOOL suppressed, id underlyingAlert) {
if (buttonClicked == TDCAlertResponseAlternate) {
[self actionContactSupport:nil];
}
[self endSheetEarly];
}];
}
- (void)_cancelEligibilityCheck
{
if (self.checkingEligibility == NO) {
return;
}
[self.licenseManagerDownloader cancelRequest];
[self _checkEligibilityCompletionBlock];
}
- (void)_checkEligibility
{
if (self.eligibility != TLOLicenseUpgradeEligibilityUnknown) {
[self _eligibilityDetermined];
return;
}
[self _checkEligibilityOfLicense:self.licenseKey];
}
- (void)_checkEligibilityOfLicense:(NSString *)licenseKey
{
NSParameterAssert(licenseKey != nil);
if (self.checkingEligibility == NO) {
self.checkingEligibility = YES;
} else {
return;
}
[self _beginProgressIndicator];
__weak TDCLicenseUpgradeEligibilitySheet *weakSelf = self;
TLOLicenseManagerDownloader *licenseManagerDownloader = [TLOLicenseManagerDownloader new];
licenseManagerDownloader.completionBlock = ^(BOOL operationSuccessful, NSUInteger statusCode, id _Nullable statusContext) {
[weakSelf _checkEligibilityCompletionBlock];
[weakSelf _extractEligibilityFromResponseWithStatusCode:statusCode statusContext:statusContext];
};
licenseManagerDownloader.isSilentOnFailure = YES;
licenseManagerDownloader.isSilentOnSuccess = YES;
[licenseManagerDownloader checkUpgradeEligibilityOfLicense:licenseKey];
self.licenseManagerDownloader = licenseManagerDownloader;
}
- (void)_checkEligibilityCompletionBlock
{
self.licenseManagerDownloader = nil;
[self _endProgressIndicator];
self.checkingEligibility = NO;
}
- (void)_extractEligibilityFromResponseWithStatusCode:(NSUInteger)statusCode statusContext:(nullable NSDictionary *)statusContext
{
LogToConsoleDebug("Status code: %{public}lu", statusCode);
#define _presentEligibilityCheckFailedSheet \
[self _presentEligibilityCheckFailedSheetWithError:errorMessage]; \
return;
/* Check for common status codes. */
if (statusCode != 0) {
NSString *errorMessage = nil;
if (statusCode == TLOLicenseManagerDownloaderRequestStatusCodeServiceIsBusy) {
errorMessage = TXTLS(@"TDCLicenseUpgradeEligibilitySheet[9uu-go]");
} else {
errorMessage = TXTLS(@"TDCLicenseUpgradeEligibilitySheet[awy-4i]", statusCode);
}
_presentEligibilityCheckFailedSheet
}
/* There is never a time a status context should be nil for this check. */
if (statusContext == nil) {
NSString *errorMessage = TXTLS(@"TDCLicenseUpgradeEligibilitySheet[z70-6s]");
_presentEligibilityCheckFailedSheet
}
/* Ensure the response we received is a type we support. */
id eligibilityObject = statusContext[@"licenseUpgradeEligibility"];
if (eligibilityObject == nil || [eligibilityObject isKindOfClass:[NSNumber class]] == NO) {
LogToConsoleError("'licenseUpgradeEligibility' is nil or not of kind 'NSNumber'");
NSString *errorMessage = TXTLS(@"TDCLicenseUpgradeEligibilitySheet[gc5-ko]");
_presentEligibilityCheckFailedSheet
}
/* Save eligibility */
NSUInteger eligibility = [eligibilityObject unsignedIntegerValue];
if (eligibility != TLOLicenseUpgradeEligibilityDiscount &&
eligibility != TLOLicenseUpgradeEligibilityFree &&
eligibility != TLOLicenseUpgradeEligibilityNot &&
eligibility != TLOLicenseUpgradeEligibilityAlreadyUpgraded)
{
NSString *errorMessage = TXTLS(@"TDCLicenseUpgradeEligibilitySheet[5s6-sb]", eligibility);
_presentEligibilityCheckFailedSheet
}
self.eligibility = eligibility;
/* Present sheet */
[self _eligibilityDetermined];
/* Inform delegate */
[self.delegate upgradeEligibilitySheetChanged:self];
#undef _presentEligibilityCheckFailedSheet
}
- (void)_eligibilityDetermined
{
if (self.eligibility == TLOLicenseUpgradeEligibilityDiscount) {
self.sheet = self.sheetEligibleDiscount;
} else if (self.eligibility == TLOLicenseUpgradeEligibilityNot) {
self.sheet = self.sheetNotEligible;
} else if (self.eligibility == TLOLicenseUpgradeEligibilityFree ||
self.eligibility == TLOLicenseUpgradeEligibilityAlreadyUpgraded)
{
self.sheet = self.sheetEligibleFree;
}
[super startSheet];
}
- (void)actionContactSupport:(id)sender
{
[self.delegate upgradeEligibilitySheetContactSupport:self];
}
- (void)actionActivateLicense:(id)sender
{
[self.delegate upgradeEligibilitySheetActivateLicense:self];
}
- (void)actionPurchaseUpgrade:(id)sender
{
[self.delegate upgradeEligibilitySheetPurchaseUpgrade:self];
}
- (void)actionPurchaseStandalone:(id)sender
{
[self.delegate upgradeEligibilitySheetPurchaseStandalone:self];
}
- (void)actionClose:(id)sender
{
[self endSheet];
}
#pragma mark -
#pragma mark NSWindow Delegate
- (void)windowWillClose:(NSNotification *)note
{
[self.delegate upgradeEligibilitySheetWillClose:self];
}
@end
#endif
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Dialogs/Preferences/TDCPreferencesController.m
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2008 - 2010 Satoshi Nakagawa
* Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "NSViewHelper.h"
#import "TXMasterController.h"
#import "TXMenuController.h"
#import "TPCPathInfoPrivate.h"
#import "TPCPreferencesLocalPrivate.h"
#import "TPCPreferencesReload.h"
#import "TPCPreferencesUserDefaults.h"
#import "TPCThemeControllerPrivate.h"
#import "THOPluginManagerPrivate.h"
#import "IRC.h"
#import "IRCClientConfig.h"
#import "IRCClient.h"
#import "IRCConnectionConfig.h"
#import "IRCWorld.h"
#import "TLOEncryptionManagerPrivate.h"
#import "TLOLocalization.h"
#import "TLOpenLink.h"
#import "TVCMainWindowPrivate.h"
#import "TVCLogControllerInlineMediaServicePrivate.H"
#import "TVCNotificationConfigurationViewControllerPrivate.h"
#import "TDCAlert.h"
#import "TDCFileTransferDialogPrivate.h"
#import "TDCPreferencesNotificationConfigurationPrivate.h"
#import "TDCPreferencesUserStyleSheetPrivate.h"
#import "TDCPreferencesControllerPrivate.h"
#if TEXTUAL_BUILT_WITH_SPARKLE_ENABLED == 1
#import
#endif
NS_ASSUME_NONNULL_BEGIN
#define _scrollbackSaveLinesMin 100
#define _scrollbackSaveLinesMax 50000
#define _scrollbackVisibleLinesMin 100
#define _scrollbackVisibleLinesMax 15000
#define _inlineMediaWidthMax 2000
#define _inlineMediaWidthMin 40
#define _inlineMediaHeightMax 6000
#define _inlineMediaHeightMin 0
#define _fileTransferPortRangeMin 1024
#define _fileTransferPortRangeMax TXMaximumTCPPort
#define _toolbarItemIndexGeneral 101
#define _toolbarItemIndexHighlights 104
#define _toolbarItemIndexNotifications 103
#define _toolbarItemIndexBehavior 102
#define _toolbarItemIndexControls 107
#define _toolbarItemIndexInterface 105
#define _toolbarItemIndexStyle 106
#define _toolbarItemIndexAddons 109
#define _toolbarItemIndexAdvanced 108
#define _toolbarItemIndexChannelManagement 108000
#define _toolbarItemIndexCommandScope 108001
#define _toolbarItemIndexFloodControl 108002
#define _toolbarItemIndexIncomingData 108003
#define _toolbarItemIndexCompatibility 108004
#define _toolbarItemIndexFileTransfers 108005
#define _toolbarItemIndexInlineMedia 108006
#define _toolbarItemIndexLogLocation 108007
#define _toolbarItemIndexDefaultIdentity 108008
#define _toolbarItemIndexDefaultIRCopMessages 108009
#define _toolbarItemIndexOffRecordMessaging 108010
#define _toolbarItemIndexHiddenPreferences 108011 // unused
#define _addonsToolbarInstalledAddonsMenuItemIndex 109000
#define _addonsToolbarItemMultiplier 995
#define _unsignedIntegerString(_value_) [NSString stringWithUnsignedInteger:_value_]
@interface TDCPreferencesController ()
@property (nonatomic, strong) IBOutlet NSArrayController *excludeKeywordsArrayController;
@property (nonatomic, strong) IBOutlet NSArrayController *highlightKeywordsArrayController;
@property (nonatomic, strong) IBOutlet NSArrayController *installedScriptsController;
@property (nonatomic, weak) IBOutlet NSButton *addExcludeKeywordButton;
@property (nonatomic, weak) IBOutlet NSButton *highlightNicknameButton;
@property (nonatomic, weak) IBOutlet NSPopUpButton *themeSelectionButton;
@property (nonatomic, weak) IBOutlet NSPopUpButton *transcriptFolderButton;
@property (nonatomic, weak) IBOutlet NSPopUpButton *fileTransferDownloadDestinationButton;
@property (nonatomic, weak) IBOutlet NSTableView *excludeKeywordsTable;
@property (nonatomic, weak) IBOutlet NSTableView *installedScriptsTable;
@property (nonatomic, weak) IBOutlet NSTableView *highlightKeywordsTable;
@property (nonatomic, weak) IBOutlet NSTextField *fileTransferManuallyEnteredIPAddressTextField;
@property (nonatomic, strong) IBOutlet NSView *contentViewGeneral;
@property (nonatomic, strong) IBOutlet NSView *contentViewHighlights;
@property (nonatomic, strong) IBOutlet NSView *contentViewNotifications;
@property (nonatomic, strong) IBOutlet NSView *contentViewBehavior;
@property (nonatomic, strong) IBOutlet NSView *contentViewControls;
@property (nonatomic, strong) IBOutlet NSView *contentViewInterface;
@property (nonatomic, strong) IBOutlet NSView *contentViewStyle;
@property (nonatomic, strong) IBOutlet NSView *contentViewInstalledAddons;
@property (nonatomic, strong) IBOutlet NSView *contentViewChannelManagement;
@property (nonatomic, strong) IBOutlet NSView *contentViewCommandScope;
@property (nonatomic, strong) IBOutlet NSView *contentViewCompatibility;
@property (nonatomic, strong) IBOutlet NSView *contentViewFloodControl;
@property (nonatomic, strong) IBOutlet NSView *contentViewIncomingData;
@property (nonatomic, strong) IBOutlet NSView *contentViewFileTransfers;
@property (nonatomic, strong) IBOutlet NSView *contentViewInlineMedia;
@property (nonatomic, strong) IBOutlet NSView *contentViewLogLocation;
@property (nonatomic, strong) IBOutlet NSView *contentViewDefaultIdentity;
@property (nonatomic, strong) IBOutlet NSView *contentViewDefaultIRCopMessages;
#if TEXTUAL_BUILT_WITH_ADVANCED_ENCRYPTION == 1
@property (nonatomic, strong) IBOutlet NSView *contentViewOffRecordMessaging;
#endif
@property (nonatomic, strong) IBOutlet NSView *contentViewHiddenPreferences;
@property (nonatomic, weak) IBOutlet NSButton *checkForUpdatesDontCheck;
@property (nonatomic, weak) IBOutlet NSButton *checkForUpdatesAutomaticallyCheck;
@property (nonatomic, weak) IBOutlet NSButton *checkForUpdatesAutomaticallyDownload;
@property (nonatomic, weak) IBOutlet NSButton *forwardNoticeToServerConsoleButton;
@property (nonatomic, weak) IBOutlet NSButton *forwardNoticeToSelectedChannelButton;
@property (nonatomic, weak) IBOutlet NSButton *forwardNoticeToQueryButton;
@property (nonatomic, weak) IBOutlet NSButton *inlineMediaEnabledButton;
@property (nonatomic, weak) IBOutlet NSStackView *contentViewGeneralStackView;
@property (nonatomic, weak) IBOutlet NSView *contentViewGeneralCheckForUpdatesView;
@property (nonatomic, weak) IBOutlet NSView *contentViewGeneralShareDataView;
@property (nonatomic, strong) IBOutlet NSToolbar *navigationToolbar;
@property (nonatomic, strong) IBOutlet NSMenu *installedAddonsMenu;
@property (nonatomic, assign) BOOL reloadingTheme;
@property (nonatomic, assign) BOOL reloadingThemeBySelection;
@property (nonatomic, weak) IBOutlet NSView *notificationControllerHostView;
@property (nonatomic, strong) IBOutlet TVCNotificationConfigurationViewController *notificationController;
@property (nonatomic, strong) TDCPreferencesUserStyleSheet *userStyleSheet;
- (IBAction)onAddExcludeKeyword:(id)sender;
- (IBAction)onAddHighlightKeyword:(id)sender; // changed
- (IBAction)onChangedAppearance:(id)sender;
- (IBAction)onChangedCheckForUpdates:(id)sender;
- (IBAction)onChangedCheckForBetaUpdates:(id)sender;
- (IBAction)onChangedChannelViewArrangement:(id)sender;
- (IBAction)onChangedDisableNicknameColorHashing:(id)sender;
- (IBAction)onChangedForwardNoticeTo:(id)sender;
- (IBAction)onChangedHighlightLogging:(id)sender;
- (IBAction)onChangedHighlightType:(id)sender;
- (IBAction)onChangedInlineMediaOption:(id)sender;
- (IBAction)onChangedInputHistoryScheme:(id)sender;
- (IBAction)onChangedMainInputTextViewFontSize:(id)sender; // changed
- (IBAction)onChangedMainWindowSegmentedController:(id)sender;
- (IBAction)onChangedScrollbackSaveLimit:(id)sender;
- (IBAction)onChangedScrollbackVisibleLimit:(id)sender;
- (IBAction)onChangedServerListUnreadBadgeColor:(id)sender;
- (IBAction)onChangedTheme:(id)sender;
- (IBAction)onChangedThemeSelection:(id)sender; // changed
- (IBAction)onChangedTranscriptFolder:(id)sender;
- (IBAction)onChangedTransparency:(id)sender;
- (IBAction)onChangedUserListModeColor:(id)sender;
- (IBAction)onChangedUserListModeSortOrder:(id)sender;
- (IBAction)onFileTransferDownloadDestinationFolderChanged:(id)sender;
- (IBAction)onFileTransferIPAddressDetectionMethodChanged:(id)sender;
- (IBAction)onModifyUserStyleSheetRules:(id)sender;
- (IBAction)onOpenPathToScripts:(id)sender;
- (IBAction)onOpenPathToTheme:(id)sender; // changed
- (IBAction)onPrefPaneSelected:(id)sender;
- (IBAction)onResetServerListUnreadBadgeColorsToDefault:(id)sender;
- (IBAction)onResetUserListModeColorsToDefaults:(id)sender;
- (IBAction)onSelectNewFont:(id)sender;
#if TEXTUAL_BUILT_WITH_ADVANCED_ENCRYPTION == 1
- (IBAction)offRecordMessagingPolicyChanged:(id)sender;
- (IBAction)offRecordMessagingOpenOfficialWebsite:(id)sender;
- (IBAction)offRecordMessagingOpenHelpDocument:(id)sender;
#endif
@end
@implementation TDCPreferencesController
- (instancetype)init
{
if ((self = [super init])) {
[self prepareInitialState];
return self;
}
return nil;
}
- (void)prepareInitialState
{
[RZMainBundle() loadNibNamed:@"TDCPreferences" owner:self topLevelObjects:nil];
}
- (void)awakeFromNib
{
[super awakeFromNib];
NSMutableArray *notifications = [NSMutableArray array];
[notifications addObject:[TDCPreferencesNotificationConfiguration objectWithEventType:TXNotificationTypeAddressBookMatch]];
[notifications addObject:@" "];
[notifications addObject:[TDCPreferencesNotificationConfiguration objectWithEventType:TXNotificationTypeConnect]];
[notifications addObject:[TDCPreferencesNotificationConfiguration objectWithEventType:TXNotificationTypeDisconnect]];
[notifications addObject:@" "];
[notifications addObject:[TDCPreferencesNotificationConfiguration objectWithEventType:TXNotificationTypeHighlight]];
[notifications addObject:@" "];
[notifications addObject:[TDCPreferencesNotificationConfiguration objectWithEventType:TXNotificationTypeInvite]];
[notifications addObject:[TDCPreferencesNotificationConfiguration objectWithEventType:TXNotificationTypeKick]];
[notifications addObject:@" "];
[notifications addObject:[TDCPreferencesNotificationConfiguration objectWithEventType:TXNotificationTypeChannelMessage]];
[notifications addObject:[TDCPreferencesNotificationConfiguration objectWithEventType:TXNotificationTypeChannelNotice]];
[notifications addObject:@" "];
[notifications addObject:[TDCPreferencesNotificationConfiguration objectWithEventType:TXNotificationTypeNewPrivateMessage]];
[notifications addObject:[TDCPreferencesNotificationConfiguration objectWithEventType:TXNotificationTypePrivateMessage]];
[notifications addObject:[TDCPreferencesNotificationConfiguration objectWithEventType:TXNotificationTypePrivateNotice]];
[notifications addObject:@" "];
[notifications addObject:[TDCPreferencesNotificationConfiguration objectWithEventType:TXNotificationTypeUserJoined]];
[notifications addObject:[TDCPreferencesNotificationConfiguration objectWithEventType:TXNotificationTypeUserParted]];
[notifications addObject:[TDCPreferencesNotificationConfiguration objectWithEventType:TXNotificationTypeUserDisconnected]];
[notifications addObject:@" "];
[notifications addObject:[TDCPreferencesNotificationConfiguration objectWithEventType:TXNotificationTypeFileTransferReceiveRequested]];
[notifications addObject:@" "];
[notifications addObject:[TDCPreferencesNotificationConfiguration objectWithEventType:TXNotificationTypeFileTransferSendSuccessful]];
[notifications addObject:[TDCPreferencesNotificationConfiguration objectWithEventType:TXNotificationTypeFileTransferReceiveSuccessful]];
[notifications addObject:@" "];
[notifications addObject:[TDCPreferencesNotificationConfiguration objectWithEventType:TXNotificationTypeFileTransferSendFailed]];
[notifications addObject:[TDCPreferencesNotificationConfiguration objectWithEventType:TXNotificationTypeFileTransferReceiveFailed]];
self.notificationController.notifications = notifications;
[self.notificationController attachToView:self.notificationControllerHostView];
[self setUpToolbarItemsAndMenus];
[self updateCheckForUpdatesMatrix];
[self updateFileTransferDownloadDestinationFolder];
[self updateForwardNoticeToMatrix];
[self updateInlineMediaEnabled];
[self updateThemeSelection];
[self updateTranscriptFolder];
[self onChangedHighlightType:nil];
[self onFileTransferIPAddressDetectionMethodChanged:nil];
self.installedScriptsTable.sortDescriptors = @[
[NSSortDescriptor sortDescriptorWithKey:@"string" ascending:YES selector:@selector(caseInsensitiveCompare:)]
];
[RZNotificationCenter() addObserver:self
selector:@selector(onThemeListDidChange:)
name:TPCThemeControllerThemeListDidChangeNotification
object:nil];
[RZNotificationCenter() addObserver:self
selector:@selector(onThemeWillReload:)
name:TVCMainWindowWillReloadThemeNotification
object:nil];
[RZNotificationCenter() addObserver:self
selector:@selector(onThemeReloadComplete:)
name:TVCMainWindowDidReloadThemeNotification
object:nil];
#if TEXTUAL_BUILT_WITH_SPARKLE_ENABLED == 0
/* Hide preferences for updates when support is not enabled. */
[self.contentViewGeneralStackView setVisibilityPriority:NSStackViewVisibilityPriorityNotVisible
forView:self.contentViewGeneralCheckForUpdatesView];
#endif
[self.contentViewGeneral layoutSubtreeIfNeeded];
[self restoreWindowFrame];
}
#pragma mark -
#pragma mark Utilities
- (void)show
{
[self show:TDCPreferencesControllerSelectionDefault];
}
- (void)show:(TDCPreferencesControllerSelection)selection
{
switch (selection) {
case TDCPreferencesControllerSelectionNotifications:
{
[self _showPane:self.contentViewNotifications selectedItem:_toolbarItemIndexNotifications];
break;
}
case TDCPreferencesControllerSelectionStyle:
{
[self _showPane:self.contentViewStyle selectedItem:_toolbarItemIndexStyle];
break;
}
case TDCPreferencesControllerSelectionHiddenPreferences:
{
[self _showPane:self.contentViewHiddenPreferences selectedItem:_toolbarItemIndexAdvanced];
break;
}
default:
{
[self _showPane:self.contentViewGeneral selectedItem:_toolbarItemIndexGeneral];
break;
}
}
}
- (void)_showPane:(NSView *)view selectedItem:(NSInteger)selectedItem
{
[self firstPane:view selectedItem:selectedItem];
[super show];
}
#pragma mark -
#pragma mark NSToolbar Delegates
- (void)setUpToolbarItemsAndMenus
{
NSArray *plugins = sharedPluginManager().pluginsWithPreferencePanes;
if (plugins.count > 0) {
[self.installedAddonsMenu addItem:[NSMenuItem separatorItem]];
}
[plugins enumerateObjectsUsingBlock:^(THOPluginItem *plugin, NSUInteger index, BOOL *stop) {
NSUInteger tagIndex = (index + _addonsToolbarItemMultiplier);
NSMenuItem *pluginMenu = [NSMenuItem menuItemWithTitle:plugin.pluginPreferencesPaneMenuItemTitle
target:self
action:@selector(onPrefPaneSelected:)];
pluginMenu.tag = tagIndex;
[self.installedAddonsMenu addItem:pluginMenu];
}];
}
- (void)onPrefPaneSelected:(id)sender
{
#define _de(matchTag, view, selectionIndex) \
case (matchTag): { \
[self firstPane:(view) selectedItem:(selectionIndex)]; \
break; \
}
switch ([sender tag]) {
_de(_toolbarItemIndexGeneral, self.contentViewGeneral, _toolbarItemIndexGeneral)
_de(_toolbarItemIndexHighlights, self.contentViewHighlights, _toolbarItemIndexHighlights)
_de(_toolbarItemIndexNotifications, self.contentViewNotifications, _toolbarItemIndexNotifications)
_de(_toolbarItemIndexBehavior, self.contentViewBehavior, _toolbarItemIndexBehavior)
_de(_toolbarItemIndexControls, self.contentViewControls, _toolbarItemIndexControls)
_de(_toolbarItemIndexInterface, self.contentViewInterface, _toolbarItemIndexInterface)
_de(_toolbarItemIndexStyle, self.contentViewStyle, _toolbarItemIndexStyle)
_de(_toolbarItemIndexChannelManagement, self.contentViewChannelManagement, _toolbarItemIndexAdvanced)
_de(_toolbarItemIndexCommandScope, self.contentViewCommandScope, _toolbarItemIndexAdvanced)
_de(_toolbarItemIndexCompatibility, self.contentViewCompatibility, _toolbarItemIndexAdvanced)
_de(_toolbarItemIndexFloodControl, self.contentViewFloodControl, _toolbarItemIndexAdvanced)
_de(_toolbarItemIndexIncomingData, self.contentViewIncomingData, _toolbarItemIndexAdvanced)
_de(_toolbarItemIndexFileTransfers, self.contentViewFileTransfers, _toolbarItemIndexAdvanced)
_de(_toolbarItemIndexInlineMedia, self.contentViewInlineMedia, _toolbarItemIndexAdvanced)
_de(_toolbarItemIndexLogLocation, self.contentViewLogLocation, _toolbarItemIndexAdvanced);
_de(_toolbarItemIndexDefaultIdentity, self.contentViewDefaultIdentity, _toolbarItemIndexAdvanced)
_de(_toolbarItemIndexDefaultIRCopMessages, self.contentViewDefaultIRCopMessages, _toolbarItemIndexAdvanced)
#if TEXTUAL_BUILT_WITH_ADVANCED_ENCRYPTION == 1
_de(_toolbarItemIndexOffRecordMessaging, self.contentViewOffRecordMessaging, _toolbarItemIndexAdvanced)
#endif
_de(_addonsToolbarInstalledAddonsMenuItemIndex, self.contentViewInstalledAddons, _toolbarItemIndexAddons)
default:
{
if ([sender tag] < _addonsToolbarItemMultiplier) {
break;
}
NSUInteger pluginIndex = ([sender tag] - _addonsToolbarItemMultiplier);
THOPluginItem *plugin = sharedPluginManager().pluginsWithPreferencePanes[pluginIndex];
NSView *preferencesView = plugin.pluginPreferencesPaneView;
[self firstPane:preferencesView selectedItem:_toolbarItemIndexAddons];
break;
}
}
#undef _de
}
- (void)firstPane:(NSView *)view selectedItem:(NSInteger)selectedItem
{
[self.window replaceContentView:view];
if (selectedItem >= 0) {
self.navigationToolbar.selectedItemIdentifier = _unsignedIntegerString(selectedItem);
} else {
self.navigationToolbar.selectedItemIdentifier = nil;
}
}
- (void)restoreWindowFrame
{
NSWindow *window = self.window;
[window saveSizeAsDefault];
[window restoreWindowStateForClass:self.class];
}
- (void)saveWindowFrame
{
NSWindow *window = self.window;
[window restoreDefaultSizeAndDisplay:NO];
[window saveWindowStateForClass:self.class];
}
#pragma mark -
#pragma mark KVC Properties
- (NSArray *)installedScripts
{
NSMutableArray *scriptsInstalled = [NSMutableArray array];
[scriptsInstalled addObjectsFromArray:sharedPluginManager().supportedAppleScriptCommands];
[scriptsInstalled addObjectsFromArray:sharedPluginManager().supportedUserInputCommands];
return scriptsInstalled.stringArrayControllerObjects;
}
- (NSString *)scrollbackSaveLimit
{
return _unsignedIntegerString([TPCPreferences scrollbackSaveLimit]);
}
- (void)setScrollbackSaveLimit:(NSString *)value
{
[TPCPreferences setScrollbackSaveLimit:value.integerValue];
}
- (NSString *)scrollbackVisibleLimit
{
return _unsignedIntegerString([TPCPreferences scrollbackVisibleLimit]);
}
- (void)setScrollbackVisibleLimit:(NSString *)value
{
[TPCPreferences setScrollbackVisibleLimit:value.integerValue];
}
- (NSString *)completionSuffix
{
return [TPCPreferences tabCompletionSuffix];
}
- (void)setCompletionSuffix:(NSString *)value
{
[TPCPreferences setTabCompletionSuffix:value];
}
- (NSString *)inlineMediaMaxWidth
{
return _unsignedIntegerString([TPCPreferences inlineMediaMaxWidth]);
}
- (NSString *)inlineMediaMaxHeight
{
return _unsignedIntegerString([TPCPreferences inlineMediaMaxHeight]);
}
- (void)setInlineMediaMaxWidth:(NSString *)value
{
[TPCPreferences setInlineMediaMaxWidth:value.integerValue];
}
- (void)setInlineMediaMaxHeight:(NSString *)value
{
[TPCPreferences setInlineMediaMaxHeight:value.integerValue];
}
- (NSString *)themeChannelViewFontName
{
NSFont *currentFont = [TPCPreferences themeChannelViewFont];
return currentFont.displayName;
}
- (CGFloat)themeChannelViewFontSize
{
return [TPCPreferences themeChannelViewFontSize];
}
- (void)setThemeChannelViewFontName:(NSString *)value
{
return;
}
- (void)setThemeChannelViewFontSize:(CGFloat)value
{
return;
}
- (NSString *)fileTransferPortRangeStart
{
return _unsignedIntegerString([TPCPreferences fileTransferPortRangeStart]);
}
- (NSString *)fileTransferPortRangeEnd
{
return _unsignedIntegerString([TPCPreferences fileTransferPortRangeEnd]);
}
- (void)setFileTransferPortRangeStart:(NSString *)value
{
[TPCPreferences setFileTransferPortRangeStart:value.integerValue];
}
- (void)setFileTransferPortRangeEnd:(NSString *)value
{
[TPCPreferences setFileTransferPortRangeEnd:value.integerValue];
}
#if TEXTUAL_BUILT_WITH_ADVANCED_ENCRYPTION == 1
- (void)setTextEncryptionIsOpportunistic:(BOOL)textEncryptionIsOpportunistic
{
[TPCPreferences setTextEncryptionIsOpportunistic:textEncryptionIsOpportunistic];
}
- (BOOL)textEncryptionIsOpportunistic
{
if ([TPCPreferences textEncryptionIsEnabled] == NO) {
return NO;
}
if ([TPCPreferences textEncryptionIsRequired]) {
return YES;
}
return [TPCPreferences textEncryptionIsOpportunistic];
}
- (BOOL)textEncryptionIsOpportunisticPreferenceEnabled
{
return ([TPCPreferences textEncryptionIsEnabled] &&
[TPCPreferences textEncryptionIsRequired] == NO);
}
- (void)setTextEncryptionIsRequired:(BOOL)textEncryptionIsRequired
{
[TPCPreferences setTextEncryptionIsRequired:textEncryptionIsRequired];
[self willChangeValueForKey:@"textEncryptionIsOpportunistic"];
[self didChangeValueForKey:@"textEncryptionIsOpportunistic"];
}
- (BOOL)textEncryptionIsRequired
{
if ([TPCPreferences textEncryptionIsEnabled] == NO) {
return NO;
}
return [TPCPreferences textEncryptionIsRequired];
}
- (BOOL)textEncryptionIsRequiredPreferenceEnabled
{
return [TPCPreferences textEncryptionIsEnabled];
}
- (void)setTextEncryptionIsEnabled:(BOOL)textEncryptionIsEnabled
{
[TPCPreferences setTextEncryptionIsEnabled:textEncryptionIsEnabled];
[self willChangeValueForKey:@"textEncryptionIsOpportunistic"];
[self willChangeValueForKey:@"textEncryptionIsOpportunisticPreferenceEnabled"];
[self willChangeValueForKey:@"textEncryptionIsRequired"];
[self willChangeValueForKey:@"textEncryptionIsRequiredPreferenceEnabled"];
[self didChangeValueForKey:@"textEncryptionIsOpportunistic"];
[self didChangeValueForKey:@"textEncryptionIsOpportunisticPreferenceEnabled"];
[self didChangeValueForKey:@"textEncryptionIsRequired"];
[self didChangeValueForKey:@"textEncryptionIsRequiredPreferenceEnabled"];
}
- (BOOL)textEncryptionIsEnabled
{
return [TPCPreferences textEncryptionIsEnabled];
}
#else
- (void)setTextEncryptionIsOpportunistic:(BOOL)textEncryptionIsOpportunistic
{
}
- (BOOL)textEncryptionIsOpportunistic
{
}
- (BOOL)textEncryptionIsOpportunisticPreferenceEnabled
{
}
- (void)setTextEncryptionIsRequired:(BOOL)textEncryptionIsRequired
{
}
- (BOOL)textEncryptionIsRequired
{
}
- (BOOL)textEncryptionIsRequiredPreferenceEnabled
{
}
- (void)setTextEncryptionIsEnabled:(BOOL)textEncryptionIsEnabled
{
}
- (BOOL)textEncryptionIsEnabled
{
}
#endif
- (BOOL)highlightCurrentNickname
{
if ([TPCPreferences highlightMatchingMethod] == TXNicknameHighlightMatchTypeRegularExpression) {
return NO;
}
return [TPCPreferences highlightCurrentNickname];
}
- (void)setHighlightCurrentNickname:(BOOL)value
{
[TPCPreferences setHighlightCurrentNickname:value];
}
- (BOOL)appNapEnabled
{
return [TPCPreferences appNapEnabled];
}
- (void)setAppNapEnabled:(BOOL)appNapEnabled
{
[TPCPreferences setAppNapEnabled:appNapEnabled];
}
- (BOOL)onlySpeakEventsForSelection
{
return [TPCPreferences onlySpeakEventsForSelection];
}
- (void)setOnlySpeakEventsForSelection:(BOOL)onlySpeakEventsForSelection
{
[TPCPreferences setOnlySpeakEventsForSelection:onlySpeakEventsForSelection];
[self willChangeValueForKey:@"channelMessageSpeakChannelName"];
[self didChangeValueForKey:@"channelMessageSpeakChannelName"];
}
- (BOOL)channelMessageSpeakChannelName
{
if ([TPCPreferences onlySpeakEventsForSelection]) {
return NO;
}
return [TPCPreferences channelMessageSpeakChannelName];
}
- (void)setChannelMessageSpeakChannelName:(BOOL)channelMessageSpeakChannelName
{
[TPCPreferences setChannelMessageSpeakChannelName:channelMessageSpeakChannelName];
}
- (BOOL)channelMessageSpeakNickname
{
return [TPCPreferences channelMessageSpeakNickname];
}
- (void)setChannelMessageSpeakNickname:(BOOL)channelMessageSpeakNickname
{
[TPCPreferences setChannelMessageSpeakNickname:channelMessageSpeakNickname];
}
- (NSColor *)serverListUnreadCountBadgeHighlightColor
{
NSColor *value = [RZUserDefaults() colorForKey:@"Server List Unread Message Count Badge Colors -> Highlight"];
if (value == nil) {
value = [NSColor clearColor];
}
return value;
}
- (void)setServerListUnreadCountBadgeHighlightColor:(NSColor *)serverListUnreadCountBadgeHighlightColor
{
NSColor *newValue = serverListUnreadCountBadgeHighlightColor;
if ([newValue isEqual:[NSColor clearColor]]) {
newValue = nil;
}
[RZUserDefaults() setColor:newValue
forKey:@"Server List Unread Message Count Badge Colors -> Highlight"];
}
- (NSColor *)userListNoModeColor
{
NSColor *value = [RZUserDefaults() colorForKey:@"User List Mode Badge Colors -> no mode"];
if (value == nil) {
value = [NSColor clearColor];
}
return value;
}
- (void)setUserListNoModeColor:(NSColor *)userListNoModeColor
{
NSColor *newValue = userListNoModeColor;
if ([newValue isEqual:[NSColor clearColor]]) {
newValue = nil;
}
[RZUserDefaults() setColor:newValue
forKey:@"User List Mode Badge Colors -> no mode"];
}
- (BOOL)logTranscript
{
return [TPCPreferences logToDisk];
}
- (void)setLogTranscript:(BOOL)logTranscript
{
[TPCPreferences setLogToDisk:logTranscript];
}
- (BOOL)inlineMediaLimitToBasics
{
return [TPCPreferences inlineMediaLimitToBasics];
}
- (void)setInlineMediaLimitToBasics:(BOOL)inlineMediaLimitToBasics
{
[TPCPreferences setInlineMediaLimitToBasics:inlineMediaLimitToBasics];
[self willChangeValueForKey:@"inlineMediaLimitBasicsToFiles"];
[self didChangeValueForKey:@"inlineMediaLimitBasicsToFiles"];
}
- (BOOL)inlineMediaLimitBasicsToFiles
{
/* Show value as enabled when basics is disabled */
if ([TPCPreferences inlineMediaLimitToBasics] == NO) {
return NO; // UI negates bool so return NO for YES
}
return [TPCPreferences inlineMediaLimitBasicsToFiles];
}
- (void)setInlineMediaLimitBasicsToFiles:(BOOL)inlineMediaLimitBasicsToFiles
{
[TPCPreferences setInlineMediaLimitBasicsToFiles:inlineMediaLimitBasicsToFiles];
}
- (BOOL)validateValue:(inout id *)value forKey:(NSString *)key error:(out NSError **)outError
{
if ([key isEqualToString:@"scrollbackSaveLimit"]) {
NSInteger valueInteger = [*value integerValue];
if (valueInteger < _scrollbackSaveLinesMin) {
*value = _unsignedIntegerString(_scrollbackSaveLinesMin);
} else if (valueInteger > _scrollbackSaveLinesMax) {
*value = _unsignedIntegerString(_scrollbackSaveLinesMax);
}
} else if ([key isEqualToString:@"scrollbackVisibleLimit"]) {
NSInteger valueInteger = [*value integerValue];
if (valueInteger < _scrollbackVisibleLinesMin && valueInteger != 0) {
*value = _unsignedIntegerString(_scrollbackVisibleLinesMin);
} else if (valueInteger > _scrollbackVisibleLinesMax) {
*value = _unsignedIntegerString(_scrollbackVisibleLinesMax);
}
} else if ([key isEqualToString:@"inlineMediaMaxWidth"]) {
NSInteger valueInteger = [*value integerValue];
if (valueInteger < _inlineMediaWidthMin) {
*value = _unsignedIntegerString(_inlineMediaWidthMin);
} else if (_inlineMediaWidthMax < valueInteger) {
*value = _unsignedIntegerString(_inlineMediaWidthMax);
}
} else if ([key isEqualToString:@"inlineMediaMaxHeight"]) {
NSInteger valueInteger = [*value integerValue];
if (valueInteger < _inlineMediaHeightMin) {
*value = _unsignedIntegerString(_inlineMediaHeightMin);
} else if (_inlineMediaHeightMax < valueInteger) {
*value = _unsignedIntegerString(_inlineMediaHeightMax);
}
} else if ([key isEqualToString:@"fileTransferPortRangeStart"]) {
NSInteger valueInteger = [*value integerValue];
NSUInteger valueRangeEnd = [TPCPreferences fileTransferPortRangeEnd];
if (valueInteger < _fileTransferPortRangeMin) {
*value = _unsignedIntegerString(_fileTransferPortRangeMin);
} else if (_fileTransferPortRangeMax < valueInteger) {
*value = _unsignedIntegerString(_fileTransferPortRangeMax);
}
valueInteger = [*value integerValue];
if (valueInteger > valueRangeEnd) {
*value = _unsignedIntegerString(valueRangeEnd);
}
} else if ([key isEqualToString:@"fileTransferPortRangeEnd"]) {
NSInteger valueInteger = [*value integerValue];
NSUInteger valueRangeStart = [TPCPreferences fileTransferPortRangeStart];
if (valueInteger < _fileTransferPortRangeMin) {
*value = _unsignedIntegerString(_fileTransferPortRangeMin);
} else if (_fileTransferPortRangeMax < valueInteger) {
*value = _unsignedIntegerString(_fileTransferPortRangeMax);
}
valueInteger = [*value integerValue];
if (valueInteger < valueRangeStart) {
*value = _unsignedIntegerString(valueRangeStart);
}
}
return YES;
}
#pragma mark -
#pragma mark File Transfer Destination Folder Popup
- (void)updateFileTransferDownloadDestinationFolder
{
TDCFileTransferDialog *transferController = [TXSharedApplication sharedFileTransferDialog];
NSURL *path = transferController.downloadDestinationURL;
NSMenuItem *item = [self.fileTransferDownloadDestinationButton itemAtIndex:0];
if (path == nil) {
item.image = nil;
item.title = TXTLS(@"TDCPreferencesController[721-ie]");
} else {
NSImage *icon = [RZWorkspace() iconForFile:path.path];
item.image = icon;
icon.size = NSMakeSize(16, 16);
item.title = path.lastPathComponent;
}
}
- (void)onFileTransferDownloadDestinationFolderChanged:(id)sender
{
TDCFileTransferDialog *transferController = [TXSharedApplication sharedFileTransferDialog];
if (self.fileTransferDownloadDestinationButton.selectedTag == 2) {
NSOpenPanel *d = [NSOpenPanel openPanel];
d.allowsMultipleSelection = NO;
d.canChooseDirectories = YES;
d.canChooseFiles = NO;
d.canCreateDirectories = YES;
d.resolvesAliases = YES;
d.prompt = TXTLS(@"Prompts[xne-79]");
[d beginSheetModalForWindow:self.window completionHandler:^(NSInteger returnCode) {
[self.fileTransferDownloadDestinationButton selectItemAtIndex:0];
if (returnCode != NSModalResponseOK) {
return;
}
NSURL *path = d.URLs[0];
NSError *bookmarkError = nil;
NSData *bookmark = [path bookmarkDataWithOptions:NSURLBookmarkCreationWithSecurityScope
includingResourceValuesForKeys:nil
relativeToURL:nil
error:&bookmarkError];
if (bookmark == nil) {
LogToConsoleError("Error creating bookmark for URL ('%{public}@'): %{public}@",
path.standardizedTildePath, bookmarkError.localizedDescription);
}
[transferController setDownloadDestinationURL:bookmark];
[self updateFileTransferDownloadDestinationFolder];
}];
}
else if (self.fileTransferDownloadDestinationButton.selectedTag == 3)
{
[self.fileTransferDownloadDestinationButton selectItemAtIndex:0];
[transferController setDownloadDestinationURL:nil];
[self updateFileTransferDownloadDestinationFolder];
}
}
#pragma mark -
#pragma mark Transcript Folder Popup
- (void)updateTranscriptFolder
{
NSURL *path = [TPCPathInfo transcriptFolderURL];
NSMenuItem *item = [self.transcriptFolderButton itemAtIndex:0];
if (path == nil) {
item.image = nil;
item.title = TXTLS(@"TDCPreferencesController[70s-c6]");
} else {
NSImage *icon = [RZWorkspace() iconForFile:path.path];
item.image = icon;
icon.size = NSMakeSize(16, 16);
item.title = path.lastPathComponent;
}
}
- (void)onChangedTranscriptFolder:(id)sender
{
if (self.transcriptFolderButton.selectedTag == 2) {
NSOpenPanel *d = [NSOpenPanel openPanel];
d.allowsMultipleSelection = NO;
d.canChooseDirectories = YES;
d.canChooseFiles = NO;
d.canCreateDirectories = YES;
d.resolvesAliases = YES;
d.prompt = TXTLS(@"Prompts[xne-79]");
[d beginSheetModalForWindow:self.window completionHandler:^(NSInteger returnCode) {
[self.transcriptFolderButton selectItemAtIndex:0];
if (returnCode != NSModalResponseOK) {
return;
}
NSURL *path = d.URLs[0];
NSError *bookmarkError = nil;
NSData *bookmark = [path bookmarkDataWithOptions:NSURLBookmarkCreationWithSecurityScope
includingResourceValuesForKeys:nil
relativeToURL:nil
error:&bookmarkError];
if (bookmark == nil) {
LogToConsoleError("Error creating bookmark for URL ('%{public}@'): %{public}@",
path.standardizedTildePath, bookmarkError.localizedDescription);
return;
}
[self setTranscriptFolderURL:bookmark];
}];
}
else if (self.transcriptFolderButton.selectedTag == 3)
{
[self.transcriptFolderButton selectItemAtIndex:0];
[self setTranscriptFolderURL:nil];
}
}
- (void)setTranscriptFolderURL:(nullable NSData *)transcriptFolderURL
{
[TPCPathInfo setTranscriptFolderURL:transcriptFolderURL];
[TPCPreferences performReloadAction:TPCPreferencesReloadActionLogTranscripts];
[self updateTranscriptFolder];
}
#pragma mark -
#pragma mark Theme
- (void)updateThemeSelection
{
[self.themeSelectionButton removeAllItems];
NSString *currentThemeName = themeController().name;
TPCThemeStorageLocation currentStorageLocation = themeController().storageLocation;
[themeController() enumerateAvailableThemesWithBlock:^(NSString *themeName, TPCThemeStorageLocation storageLocation, BOOL multipleVariants, BOOL *stop) {
NSString *displayName = themeName;
if (multipleVariants) {
displayName = [NSString stringWithFormat:@"%@ (%@)",
themeName, [TPCThemeController descriptionForStorageLocation:storageLocation]];
}
NSMenuItem *item = [NSMenuItem menuItemWithTitle:displayName target:nil action:nil];
item.representedObject =
@{
@"themeName" : themeName,
@"storageLocation" : @(storageLocation)
};
if ([currentThemeName isEqualToString:themeName] &&
currentStorageLocation == storageLocation)
{
item.tag = 100; // Tag for item to select
}
[self.themeSelectionButton.menu addItem:item];
}];
[self.themeSelectionButton selectItemWithTag:100];
}
- (void)onChangedThemeSelection:(id)sender
{
NSMenuItem *selectedItem = self.themeSelectionButton.selectedItem;
NSDictionary *context = selectedItem.representedObject;
NSString *newThemeName = context[@"themeName"];
TPCThemeStorageLocation newStorageLocation = [context unsignedIntegerForKey:@"storageLocation"];
NSString *newTheme = [TPCThemeController buildFilename:newThemeName forStorageLocation:newStorageLocation];
NSString *currentTheme = [TPCPreferences themeName];
if ([currentTheme isEqualToString:newTheme]) {
return;
}
[TPCPreferences setThemeName:newTheme];
self.reloadingThemeBySelection = YES;
[self onChangedTheme:nil];
}
- (void)onChangedThemeSelectionReloadComplete:(NSNotification *)notification
{
NSMutableString *forcedValuesMutable = [NSMutableString string];
if ([TPCPreferences themeNicknameFormatPreferenceUserConfigurable] == NO) {
[forcedValuesMutable appendString:TXTLS(@"TDCPreferencesController[77t-de]")];
[forcedValuesMutable appendString:@"\n"];
}
if ([TPCPreferences themeTimestampFormatPreferenceUserConfigurable] == NO) {
[forcedValuesMutable appendString:TXTLS(@"TDCPreferencesController[ddh-hr]")];
[forcedValuesMutable appendString:@"\n"];
}
if ([TPCPreferences themeChannelViewFontPreferenceUserConfigurable] == NO) {
[forcedValuesMutable appendString:TXTLS(@"TDCPreferencesController[we8-i8]")];
[forcedValuesMutable appendString:@"\n"];
}
NSString *forcedValues = forcedValuesMutable.trim;
if (forcedValues.length == 0) {
return;
}
NSString *currentTheme = [TPCPreferences themeName];
NSString *themeName = [TPCThemeController extractThemeName:currentTheme];
[TDCAlert alertSheetWithWindow:[NSApp keyWindow]
body:TXTLS(@"TDCPreferencesController[q4o-2f]", themeName, forcedValues)
title:TXTLS(@"TDCPreferencesController[uc0-z7]")
defaultButton:TXTLS(@"Prompts[c7s-dq]")
alternateButton:nil
otherButton:nil
suppressionKey:@"theme_override_info"
suppressionText:nil
completionBlock:nil];
}
- (void)onSelectNewFont:(id)sender
{
NSFont *currentFont = [TPCPreferences themeChannelViewFont];
[RZFontManager() setSelectedFont:currentFont isMultiple:NO];
[RZFontManager() orderFrontFontPanel:self];
RZFontManager().action = @selector(onChangedChannelViewFont:);
}
- (void)onChangedChannelViewFont:(NSFontManager *)sender
{
NSFont *currentFont = [TPCPreferences themeChannelViewFont];
NSFont *newFont = [sender convertFont:currentFont];
[self willChangeValueForKey:@"themeChannelViewFontName"];
[self willChangeValueForKey:@"themeChannelViewFontSize"];
[TPCPreferences setThemeChannelViewFontName:newFont.fontName];
[TPCPreferences setThemeChannelViewFontSize:newFont.pointSize];
[self didChangeValueForKey:@"themeChannelViewFontName"];
[self didChangeValueForKey:@"themeChannelViewFontSize"];
[self onChangedTheme:nil];
}
- (void)onChangedTransparency:(id)sender
{
[mainWindow() updateAlphaValueToReflectPreferences];
}
#pragma mark -
#pragma mark User Style Sheet Rules
- (void)onModifyUserStyleSheetRules:(id)sender
{
TDCPreferencesUserStyleSheet *sheet = [[TDCPreferencesUserStyleSheet alloc] initWithWindow:self.window];
sheet.delegate = (id)self;
[sheet start];
self.userStyleSheet = sheet;
}
- (void)userStyleSheetRulesChanged:(TDCPreferencesUserStyleSheet *)sender
{
[self onChangedTheme:nil];
}
- (void)userStyleSheetWillClose:(TDCPreferencesUserStyleSheet *)sender
{
self.userStyleSheet = nil;
}
#pragma mark -
#pragma mark Forward Notice To
- (void)updateForwardNoticeToMatrix
{
TXNoticeSendLocation location = [TPCPreferences locationToSendNotices];
self.forwardNoticeToServerConsoleButton.state = (location == TXNoticeSendLocationServerConsole);
self.forwardNoticeToSelectedChannelButton.state = (location == TXNoticeSendLocationSelectedChannel);
self.forwardNoticeToQueryButton.state = (location == TXNoticeSendLocationQuery);
}
- (void)onChangedForwardNoticeTo:(id)sender
{
[TPCPreferences setLocationToSendNotices:[sender tag]];
}
#pragma mark -
#pragma mark Updates
- (void)updateCheckForUpdatesMatrix
{
#if TEXTUAL_BUILT_WITH_SPARKLE_ENABLED == 1
SPUUpdater *updater = masterController().updateController.updater;
self.checkForUpdatesAutomaticallyDownload.state = updater.automaticallyDownloadsUpdates;
self.checkForUpdatesAutomaticallyCheck.state = updater.automaticallyChecksForUpdates;
self.checkForUpdatesDontCheck.state = (updater.automaticallyDownloadsUpdates == NO &&
updater.automaticallyChecksForUpdates == NO);
#endif
}
- (void)onChangedCheckForUpdates:(id)sender
{
#if TEXTUAL_BUILT_WITH_SPARKLE_ENABLED == 1
SPUUpdater *updater = masterController().updateController.updater;
updater.automaticallyChecksForUpdates = (self.checkForUpdatesAutomaticallyCheck.state == NSControlStateValueOn);
updater.automaticallyDownloadsUpdates = (self.checkForUpdatesAutomaticallyDownload.state == NSControlStateValueOn);
#endif
}
- (void)onChangedCheckForBetaUpdates:(id)sender
{
#if TEXTUAL_BUILT_WITH_SPARKLE_ENABLED == 1
[TPCPreferences performReloadAction:TPCPreferencesReloadActionSparkleFrameworkFeedURL];
if ([TPCPreferences receiveBetaUpdates]) {
[menuController() checkForUpdates:nil];
}
#endif
}
#pragma mark -
#pragma mark Actions
- (void)onChangedDisableNicknameColorHashing:(id)sender
{
[self onChangedTheme:nil];
}
#if TEXTUAL_BUILT_WITH_ADVANCED_ENCRYPTION == 1
- (void)offRecordMessagingPolicyChanged:(id)sender
{
[TPCPreferences performReloadAction:TPCPreferencesReloadActionEncryptionPolicy];
}
- (void)offRecordMessagingOpenOfficialWebsite:(id)sender
{
[TLOpenLink openWithString:@"https://otr.cypherpunks.ca/"];
}
- (void)offRecordMessagingOpenHelpDocument:(id)sender
{
[TLOpenLink openWithString:@"https://help.codeux.com/textual/Off-the-Record-Messaging.kb"];
}
#endif
- (void)onChangedHighlightType:(id)sender
{
[self willChangeValueForKey:@"highlightCurrentNickname"];
[self didChangeValueForKey:@"highlightCurrentNickname"];
if ([TPCPreferences highlightMatchingMethod] == TXNicknameHighlightMatchTypeRegularExpression) {
self.highlightNicknameButton.enabled = NO;
} else {
self.highlightNicknameButton.enabled = YES;
}
}
- (void)editTableView:(NSTableView *)tableView
{
NSInteger rowSelection = (tableView.numberOfRows - 1);
[tableView scrollRowToVisible:rowSelection];
[tableView editColumn:0 row:rowSelection withEvent:nil select:YES];
}
- (void)onAddHighlightKeyword:(id)sender
{
[self.highlightKeywordsArrayController add:nil];
XRPerformBlockAsynchronouslyOnMainQueue(^{
[self editTableView:self.highlightKeywordsTable];
});
}
- (void)onAddExcludeKeyword:(id)sender
{
[self.excludeKeywordsArrayController add:nil];
XRPerformBlockAsynchronouslyOnMainQueue(^{
[self editTableView:self.excludeKeywordsTable];
});
}
+ (void)openProxySettingsInSystemPreferences
{
AEDesc aeDesc = { typeNull, NULL };
OSStatus aeDescStatus = AECreateDesc('ptru', "Proxies", 7, &aeDesc);
if (aeDescStatus != noErr) {
LogToConsoleError("aeDescStatus returned value other than noErr: %{public}i", aeDescStatus);
return;
}
NSURL *prefPaneURL = [NSURL fileURLWithPath:@"/System/Library/PreferencePanes/Network.prefPane"];
LSLaunchURLSpec launchSpec = { 0 };
launchSpec.appURL = NULL;
launchSpec.asyncRefCon = NULL;
launchSpec.itemURLs = (__bridge CFArrayRef)@[prefPaneURL];
launchSpec.launchFlags = (kLSLaunchAsync | kLSLaunchDontAddToRecents);
launchSpec.passThruParams = &aeDesc;
(void)LSOpenFromURLSpec(&launchSpec, NULL);
}
- (void)updateInlineMediaEnabled
{
if ([TPCPreferences showInlineMedia]) {
self.inlineMediaEnabledButton.state = NSControlStateValueOn;
} else {
self.inlineMediaEnabledButton.state = NSControlStateValueOff;
}
}
- (void)onChangedInlineMediaOption:(id)sender
{
if (self.inlineMediaEnabledButton.state == NSControlStateValueOff) {
[TPCPreferences setShowInlineMedia:NO];
[self onChangedTheme:nil];
return;
}
[TVCLogControllerInlineMediaService askPermissionToEnableInlineMediaWithCompletionBlock:^(BOOL granted) {
if (granted) {
[TPCPreferences setShowInlineMedia:YES];
[self onChangedTheme:nil];
} else {
self.inlineMediaEnabledButton.state = NSControlStateValueOff;
}
}];
}
- (void)onResetUserListModeColorsToDefaults:(id)sender
{
[RZUserDefaults() setObject:nil forKey:@"User List Mode Badge Colors -> +y"];
[RZUserDefaults() setObject:nil forKey:@"User List Mode Badge Colors -> +q"];
[RZUserDefaults() setObject:nil forKey:@"User List Mode Badge Colors -> +a"];
[RZUserDefaults() setObject:nil forKey:@"User List Mode Badge Colors -> +o"];
[RZUserDefaults() setObject:nil forKey:@"User List Mode Badge Colors -> +h"];
[RZUserDefaults() setObject:nil forKey:@"User List Mode Badge Colors -> +v"];
[RZUserDefaults() setObject:nil forKey:@"User List Mode Badge Colors -> no mode"];
[self onChangedUserListModeColor:nil];
}
- (void)onResetServerListUnreadBadgeColorsToDefault:(id)sender
{
[self willChangeValueForKey:@"serverListUnreadCountBadgeHighlightColor"];
[RZUserDefaults() setObject:nil forKey:@"Server List Unread Message Count Badge Colors -> Highlight"];
[self didChangeValueForKey:@"serverListUnreadCountBadgeHighlightColor"];
[self onChangedServerListUnreadBadgeColor:sender];
}
- (void)onChangedInputHistoryScheme:(id)sender
{
[TPCPreferences performReloadAction:TPCPreferencesReloadActionInputHistoryScope];
}
- (void)onChangedAppearance:(id)sender
{
[TPCPreferences performReloadAction:TPCPreferencesReloadActionAppearance];
}
- (void)onChangedTheme:(id)sender
{
[TPCPreferences performReloadAction:(TPCPreferencesReloadActionStyle | TPCPreferencesReloadActionTextDirection)];
}
- (void)onThemeWillReload:(NSNotification *)notification
{
self.reloadingTheme = YES;
}
- (void)onThemeReloadComplete:(NSNotification *)notification
{
self.reloadingTheme = NO;
if (self.reloadingThemeBySelection) {
self.reloadingThemeBySelection = NO;
[self onChangedThemeSelectionReloadComplete:notification];
}
}
- (void)onChangedChannelViewArrangement:(id)sender
{
[TPCPreferences performReloadAction:TPCPreferencesReloadActionChannelViewArrangement];
}
- (void)onChangedMainWindowSegmentedController:(id)sender
{
[TPCPreferences performReloadAction:TPCPreferencesReloadActionTextFieldSegmentedControllerOrigin];
}
- (void)onChangedUserListModeColor:(id)sender
{
static NSDictionary *preferenceMap = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
preferenceMap = @{
@(10) : @"User List Mode Badge Colors -> +y",
@(9) : @"User List Mode Badge Colors -> +q",
@(8) : @"User List Mode Badge Colors -> +a",
@(7) : @"User List Mode Badge Colors -> +o",
@(6) : @"User List Mode Badge Colors -> +h",
@(5) : @"User List Mode Badge Colors -> +v",
@(4) : @"User List Mode Badge Colors -> no mode"
};
});
NSString *preferenceKey = preferenceMap[@([sender tag])];
/* -onResetUserListModeColorsToDefaults: passes nil sender */
if (preferenceKey == nil) {
[TPCPreferences performReloadAction:(TPCPreferencesReloadActionMemberListUserBadges | TPCPreferencesReloadActionMemberList)];
} else {
[TPCPreferences performReloadAction:TPCPreferencesReloadActionMemberListUserBadges forKey:preferenceKey];
}
}
- (void)onChangedMainInputTextViewFontSize:(id)sender
{
[TPCPreferences performReloadAction:TPCPreferencesReloadActionTextFieldFontSize];
}
- (void)onFileTransferIPAddressDetectionMethodChanged:(id)sender
{
TXFileTransferIPAddressMethodDetection detectionMethod = [TPCPreferences fileTransferIPAddressDetectionMethod];
self.fileTransferManuallyEnteredIPAddressTextField.enabled = (detectionMethod == TXFileTransferIPAddressMethodManual);
}
- (void)onChangedHighlightLogging:(id)sender
{
[TPCPreferences performReloadAction:TPCPreferencesReloadActionHighlightLogging];
}
- (void)onChangedUserListModeSortOrder:(id)sender
{
[TPCPreferences performReloadAction:TPCPreferencesReloadActionMemberListSortOrder];
}
- (void)onChangedServerListUnreadBadgeColor:(id)sender
{
[TPCPreferences performReloadAction:TPCPreferencesReloadActionServerListUnreadBadges];
}
- (void)onChangedScrollbackSaveLimit:(id)sender
{
[TPCPreferences performReloadAction:TPCPreferencesReloadActionScrollbackSaveLimit];
}
- (void)onChangedScrollbackVisibleLimit:(id)sender
{
[TPCPreferences performReloadAction:TPCPreferencesReloadActionScrollbackVisibleLimit];
}
- (void)onOpenPathToScripts:(id)sender
{
[RZWorkspace() openURL:[TPCPathInfo groupContainerApplicationSupportURL]];
}
- (void)openPathToThemesCallback:(TDCAlertResponse)returnCode withOriginalAlert:(NSAlert *)originalAlert
{
NSParameterAssert(originalAlert != nil);
if (returnCode == TDCAlertResponseDefault) {
[self openPathToTheme];
}
if (returnCode == TDCAlertResponseAlternate) {
[self onModifyUserStyleSheetRules:nil];
}
if (returnCode == TDCAlertResponseOther) {
[originalAlert.window orderOut:nil];
[themeController() copyActiveThemeToDestinationLocation:TPCThemeStorageLocationCustom reloadOnCopy:YES openOnCopy:YES];
}
}
- (void)onOpenPathToTheme:(id)sender
{
if (themeController().bundledTheme) {
[TDCAlert alertSheetWithWindow:NSApp.keyWindow
body:TXTLS(@"TDCPreferencesController[ojj-ap]")
title:TXTLS(@"TDCPreferencesController[5jv-aw]")
defaultButton:TXTLS(@"TDCPreferencesController[6ws-av]")
alternateButton:TXTLS(@"TDCPreferencesController[aib-iy]")
otherButton:TXTLS(@"TDCPreferencesController[dj8-1t]")
completionBlock:^(TDCAlertResponse buttonClicked, BOOL suppressed, id underlyingAlert) {
[self openPathToThemesCallback:buttonClicked withOriginalAlert:underlyingAlert];
}];
return;
}
[self openPathToTheme];
}
- (void)openPathToTheme
{
NSURL *fileURL = themeController().originalURL;
[RZWorkspace() openURL:fileURL];
}
- (void)onThemeListDidChange:(NSNotification *)aNote
{
[self updateThemeSelection];
}
#pragma mark -
#pragma mark NSWindow Delegate
- (void)windowWillClose:(NSNotification *)note
{
[RZNotificationCenter() removeObserver:self];
[self saveWindowFrame];
if ([self.delegate respondsToSelector:@selector(preferencesDialogWillClose:)]) {
[self.delegate preferencesDialogWillClose:self];
}
}
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Dialogs/Preferences/TDCPreferencesNotificationConfiguration.m
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2008 - 2010 Satoshi Nakagawa
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "TPCPreferencesLocalPrivate.h"
#import "TDCPreferencesNotificationConfigurationPrivate.h"
NS_ASSUME_NONNULL_BEGIN
@implementation TDCPreferencesNotificationConfiguration
+ (TDCPreferencesNotificationConfiguration *)objectWithEventType:(TXNotificationType)eventType
{
return [[self alloc] initWithEventType:eventType];
}
- (nullable NSString *)alertSound
{
NSString *sound = [TPCPreferences soundForEvent:self.eventType];
if (sound == nil) {
return TXNoAlertSoundPreferenceValue;
}
return sound;
}
- (void)setAlertSound:(nullable NSString *)alertSound
{
[TPCPreferences setSound:alertSound forEvent:self.eventType];
}
- (NSUInteger)pushNotification
{
return [TPCPreferences notificationEnabledForEvent:self.eventType];
}
- (void)setPushNotification:(NSUInteger)pushNotification
{
[TPCPreferences setNotificationEnabled:pushNotification forEvent:self.eventType];
}
- (NSUInteger)speakEvent
{
return [TPCPreferences speakEvent:self.eventType];
}
- (void)setSpeakEvent:(NSUInteger)speakEvent
{
[TPCPreferences setEventIsSpoken:speakEvent forEvent:self.eventType];
}
- (NSUInteger)disabledWhileAway
{
return [TPCPreferences disabledWhileAwayForEvent:self.eventType];
}
- (void)setDisabledWhileAway:(NSUInteger)disabledWhileAway
{
[TPCPreferences setDisabledWhileAway:disabledWhileAway forEvent:self.eventType];
}
- (NSUInteger)bounceDockIcon
{
return [TPCPreferences bounceDockIconForEvent:self.eventType];
}
- (void)setBounceDockIcon:(NSUInteger)bounceDockIcon
{
[TPCPreferences setBounceDockIcon:bounceDockIcon forEvent:self.eventType];
}
- (NSUInteger)bounceDockIconRepeatedly
{
return [TPCPreferences bounceDockIconRepeatedlyForEvent:self.eventType];
}
- (void)setBounceDockIconRepeatedly:(NSUInteger)bounceDockIconRepeatedly
{
[TPCPreferences setBounceDockIconRepeatedly:bounceDockIconRepeatedly forEvent:self.eventType];
}
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Dialogs/Preferences/TDCPreferencesUserStyleSheet.m
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2019 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "TLOLocalization.h"
#import "TPCPreferencesLocalPrivate.h"
#import "TDCPreferencesUserStyleSheetPrivate.h"
NS_ASSUME_NONNULL_BEGIN
@interface TDCPreferencesUserStyleSheet ()
@property (nonatomic, unsafe_unretained) IBOutlet NSTextView *rulesTextView;
@property (nonatomic, assign) BOOL rulesChanged;
@property (nonatomic, copy, readonly) NSString *defaultRules;
@end
@implementation TDCPreferencesUserStyleSheet
- (instancetype)initWithWindow:(nullable NSWindow *)window
{
if ((self = [super initWithWindow:window])) {
[self prepareInitialState];
return self;
}
return nil;
}
- (void)prepareInitialState
{
[RZMainBundle() loadNibNamed:@"TDCPreferencesUserStyleSheet" owner:self topLevelObjects:nil];
self.rulesTextView.font = [NSFont systemFontOfSize:13.0];
self.rulesTextView.textContainerInset = NSMakeSize(1, 3);
[self loadRules];
}
- (void)start
{
[self startSheet];
}
- (void)textDidChange:(NSNotification *)aNotification
{
if (aNotification.object == self.rulesTextView) {
self.rulesChanged = YES;
}
}
- (void)loadRules
{
NSString *rules = [TPCPreferences themeUserStyleSheetRules];
/* We can define the default rules in the defaults property list
but we don't do that for this preference so that it doesn't append
to the HTML unless the user entered a value. It is easier to do
that here versus making a comparison to the default in higher up. */
if (rules == nil) {
rules = self.defaultRules;
}
self.rulesTextView.string = rules;
self.rulesChanged = NO;
}
- (void)saveRules
{
NSString *rules = self.rulesTextView.string.trim;
if (rules.length == 0 || [rules isEqualToString:self.defaultRules]) {
rules = nil;
}
[TPCPreferences setThemeUserStyleSheetRules:rules];
if ([self.delegate respondsToSelector:@selector(userStyleSheetRulesChanged:)]) {
[self.delegate userStyleSheetRulesChanged:self];
}
}
- (void)ok:(id)sender
{
if (self.rulesChanged) {
[self saveRules];
}
[super ok:nil];
}
- (NSString *)defaultRules
{
return TXTLS(@"TDCPreferencesUserStyleSheet[q4s-3m]");
}
#pragma mark -
#pragma mark NSWindow Delegate
- (void)windowWillClose:(NSNotification *)note
{
if ([self.delegate respondsToSelector:@selector(userStyleSheetWillClose:)]) {
[self.delegate userStyleSheetWillClose:self];
}
}
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Dialogs/Server Endpoint/TDCServerEndpointListSheet.m
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "IRCServer.h"
#import "TVCBasicTableView.h"
#import "TDCServerEndpointListSheetPrivate.h"
NS_ASSUME_NONNULL_BEGIN
#define _endpointEntryTableDragToken @"TDCServerEndpointListSheetEntryTableDragToken"
@interface TDCServerEndpointListSheet ()
@property (nonatomic, strong) IBOutlet NSArrayController *entryTableController;
@property (nonatomic, weak) IBOutlet TVCBasicTableView *entryTable;
@property (nonatomic, weak) IBOutlet NSSegmentedControl *entryActionsSegmentedControl;
- (IBAction)entryActionsSegmentedControlClicked:(id)sender;
@end
@implementation TDCServerEndpointListSheet
- (instancetype)initWithWindow:(nullable NSWindow *)window
{
if ((self = [super initWithWindow:window])) {
[self prepareInitialState];
return self;
}
return nil;
}
- (void)prepareInitialState
{
[RZMainBundle() loadNibNamed:@"TDCServerEndpointListSheet" owner:self topLevelObjects:nil];
[self.entryTable registerForDraggedTypes:@[_endpointEntryTableDragToken]];
[self.entryTableController addObserver:self
forKeyPath:@"canRemove"
options:(NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew)
context:NULL];
}
- (void)startWithServerList:(NSArray *)serverList
{
NSParameterAssert(serverList != nil);
for (IRCServer *server in serverList) {
[self.entryTableController addObject:[server mutableCopy]];
}
[self startSheet];
}
- (void)ok:(id)sender
{
NSArray *serverListIn = self.entryTableController.arrangedObjects;
NSMutableArray *serverListOut =
[[NSMutableArray alloc] initWithCapacity:serverListIn.count];
for (IRCServerMutable *server in serverListIn) {
/* New entries that are blank do not perform validation
because nothing technically has changed. Instead of
doing some complex workaround, let's just ditch
objects with an empty server address. */
if (server.serverAddress.length == 0) {
continue;
}
[serverListOut addObject:[server copy]];
}
if ([self.delegate respondsToSelector:@selector(serverEndpointListSheet:onOk:)]) {
[self.delegate serverEndpointListSheet:self onOk:[serverListOut copy]];
}
[super ok:sender];
}
- (void)observeValueForKeyPath:(nullable NSString *)keyPath ofObject:(nullable id)object change:(nullable NSDictionary *)change context:(nullable void *)context
{
if ([keyPath isEqualToString:@"canRemove"]) {
[self updateEntryActionsSegmentedControlEnabledState];
}
}
#pragma mark -
#pragma mark Entry Management
- (void)updateEntryActionsSegmentedControlEnabledState
{
[self.entryActionsSegmentedControl setEnabled:self.entryTableController.canRemove forSegment:1];
}
- (void)entryActionsSegmentedControlClicked:(id)sender
{
NSInteger selectedSegment = [sender selectedSegment];
if (selectedSegment == 0) {
[self addEntry];
} else if (selectedSegment == 1) {
[self removeSelectedEntry];
}
}
- (void)addEntry
{
IRCServerMutable *newEntry = [IRCServerMutable new];
[self.entryTableController addObject:newEntry];
/* Edit column next pass on the main thread to allow the
-addObject to register properly. */
XRPerformBlockAsynchronouslyOnMainQueue(^{
NSTableView *tableView = self.entryTable;
NSInteger rowSelection = (tableView.numberOfRows - 1);
[tableView scrollRowToVisible:rowSelection];
[tableView editColumn:0 row:rowSelection withEvent:nil select:YES];
});
}
- (void)removeSelectedEntry
{
NSIndexSet *selectedRows = self.entryTable.selectedRowIndexes;
[self.entryTableController removeObjectsAtArrangedObjectIndexes:selectedRows];
}
#pragma mark -
#pragma mark Table View Delegate
- (BOOL)tableView:(NSTableView *)tableView writeRowsWithIndexes:(NSIndexSet *)rowIndexes toPasteboard:(NSPasteboard *)pasteboard
{
NSData *draggedData = [NSKeyedArchiver archivedDataWithRootObject:rowIndexes];
[pasteboard declareTypes:@[_endpointEntryTableDragToken] owner:self];
[pasteboard setData:draggedData forType:_endpointEntryTableDragToken];
return YES;
}
- (NSDragOperation)tableView:(NSTableView *)tableView validateDrop:(id)info proposedRow:(NSInteger)row proposedDropOperation:(NSTableViewDropOperation)dropOperation
{
return NSDragOperationGeneric;
}
- (BOOL)tableView:(NSTableView *)tableView acceptDrop:(id )info row:(NSInteger)row dropOperation:(NSTableViewDropOperation)dropOperation
{
NSPasteboard *pasteboard = [info draggingPasteboard];
NSData *draggedData = [pasteboard dataForType:_endpointEntryTableDragToken];
NSIndexSet *draggedRowIndexes = [NSKeyedUnarchiver unarchiveObjectWithData:draggedData];
NSUInteger draggedRowIndex = draggedRowIndexes.firstIndex;
[self.entryTableController moveObjectAtArrangedObjectIndex:draggedRowIndex toIndex:row];
return YES;
}
#pragma mark -
#pragma mark NSWindow Delegate
- (void)windowWillClose:(NSNotification *)note
{
[self.entryTableController removeObserver:self forKeyPath:@"canRemove"];
if ([self.delegate respondsToSelector:@selector(serverEndpointListSheetWillClose:)]) {
[self.delegate serverEndpointListSheetWillClose:self];
}
}
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Dialogs/Server Endpoint/TDCServerEndpointListSheetTable.m
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "IRCServer.h"
#import "NSStringHelper.h"
#import "TLOLocalization.h"
#import "TDCServerEndpointListSheetTablePrivate.h"
NS_ASSUME_NONNULL_BEGIN
@interface TDCServerEndpointListSheetTableCellView ()
@property (nonatomic, copy) NSString *serverAddress;
@property (nonatomic, copy) NSString *serverPort;
@property (nonatomic, copy) NSNumber *prefersSecuredConnection;
@property (nonatomic, copy) NSString *serverPassword;
@property (nonatomic, assign) BOOL observersRegistered;
@end
@implementation TDCServerEndpointListSheetTableCellView
- (BOOL)validateValue:(inout id *)ioValue forKeyPath:(NSString *)inKeyPath error:(out NSError **)outError
{
if ([inKeyPath isEqualToString:@"serverAddress"]) {
if (((NSString *)*ioValue).isValidInternetAddress == NO) {
if (outError) {
*outError = [NSError errorWithDomain:TXErrorDomain
code:71013
userInfo:@{
NSLocalizedDescriptionKey : TXTLS(@"TDCServerEndpointListSheet[iis-gr]"),
NSLocalizedRecoverySuggestionErrorKey : TXTLS(@"TDCServerEndpointListSheet[k0c-3u]")}
];
}
return NO;
}
} else if ([inKeyPath isEqualToString:@"serverPort"]) {
if (((NSString *)*ioValue).isValidInternetPort == NO) {
if (outError) {
*outError = [NSError errorWithDomain:TXErrorDomain
code:71014
userInfo:@{
NSLocalizedDescriptionKey : TXTLS(@"TDCServerEndpointListSheet[qeb-ip]"),
NSLocalizedRecoverySuggestionErrorKey : TXTLS(@"TDCServerEndpointListSheet[ox2-od]")}
];
}
return NO;
}
}
return YES;
}
- (NSString *)serverAddress
{
IRCServerMutable *objectValue = self.objectValue;
if (objectValue == nil) {
return @"";
}
return objectValue.serverAddress;
}
- (void)setServerAddress:(NSString *)serverAddress
{
IRCServerMutable *objectValue = self.objectValue;
if (objectValue == nil) {
return;
}
objectValue.serverAddress = serverAddress;
}
- (NSString *)serverPort
{
IRCServerMutable *objectValue = self.objectValue;
if (objectValue == nil) {
return @"";
}
return [NSString stringWithUnsignedShort:objectValue.serverPort];
}
- (void)setServerPort:(NSString *)serverPort
{
IRCServerMutable *objectValue = self.objectValue;
if (objectValue == nil) {
return;
}
objectValue.serverPort = (uint16_t)serverPort.integerValue;
}
- (NSNumber *)prefersSecuredConnection
{
IRCServerMutable *objectValue = self.objectValue;
if (objectValue == nil) {
return @(NSControlStateValueOff);
}
if (objectValue.prefersSecuredConnection) {
return @(NSControlStateValueOn);
} else {
return @(NSControlStateValueOff);
}
}
- (void)setPrefersSecuredConnection:(NSNumber *)prefersSecuredConnection
{
IRCServerMutable *objectValue = self.objectValue;
if (objectValue == nil) {
return;
}
BOOL l_prefersSecuredConnection =
(prefersSecuredConnection.unsignedIntegerValue == NSControlStateValueOn);
if (l_prefersSecuredConnection) {
objectValue.prefersSecuredConnection = YES;
if (objectValue.serverPort == 6667) {
objectValue.serverPort = 6697;
}
} else {
objectValue.prefersSecuredConnection = NO;
if (objectValue.serverPort == 6697) {
objectValue.serverPort = 6667;
}
}
}
- (NSString *)serverPassword
{
IRCServerMutable *objectValue = self.objectValue;
if (objectValue == nil) {
return @"";
}
NSString *serverPassword = objectValue.serverPassword;
if (serverPassword == nil) {
return @"";
}
return serverPassword;
}
- (void)setServerPassword:(NSString *)serverPassword
{
IRCServerMutable *objectValue = self.objectValue;
if (objectValue == nil) {
return;
}
objectValue.serverPassword = serverPassword;
}
- (void)setObjectValue:(nullable id)objectValue
{
[self stopObservingObjectValue];
super.objectValue = objectValue;
[self startObservingObjectValue];
}
- (void)startObservingObjectValue
{
NSString *keyPath = self.identifier;
[self willChangeValueForKey:keyPath];
[self didChangeValueForKey:keyPath];
IRCServerMutable *objectValue = self.objectValue;
if (objectValue == nil) {
return;
}
[objectValue addObserver:self forKeyPath:keyPath options:NSKeyValueObservingOptionNew context:NULL];
self.observersRegistered = YES;
}
- (void)stopObservingObjectValue
{
if (self.observersRegistered == NO) {
return;
}
NSString *keyPath = self.identifier;
IRCServerMutable *objectValue = self.objectValue;
[objectValue removeObserver:self forKeyPath:keyPath];
self.observersRegistered = NO;
}
- (void)observeValueForKeyPath:(nullable NSString *)keyPath ofObject:(nullable id)object change:(nullable NSDictionary *)change context:(nullable void *)context
{
if ([keyPath isEqualToString:@"serverPort"]) {
[self willChangeValueForKey:@"serverPort"];
[self didChangeValueForKey:@"serverPort"];
}
}
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Dialogs/TDCAboutDialog.m
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "TXMasterController.h"
#import "TXMenuController.h"
#import "TLOLocalization.h"
#import "TPCApplicationInfo.h"
#import "TDCAboutDialogPrivate.h"
NS_ASSUME_NONNULL_BEGIN
@interface TDCAboutDialog ()
@property (nonatomic, weak) IBOutlet NSTextField *versionInfoTextField;
- (IBAction)displayAcknowledgements:(id)sender;
@end
@implementation TDCAboutDialog
- (instancetype)init
{
if ((self = [super init])) {
[self prepareInitialState];
return self;
}
return nil;
}
- (void)prepareInitialState
{
[RZMainBundle() loadNibNamed:@"TDCAboutDialog" owner:self topLevelObjects:nil];
NSString *bundleVersion = [TPCApplicationInfo applicationVersionShort];
self.versionInfoTextField.stringValue = TXTLS(@"TDCAboutDialog[zjd-al]", bundleVersion);
}
- (void)show
{
[self.window restoreWindowStateForClass:self.class];
[super show];
}
- (void)displayAcknowledgements:(id)sender
{
[menuController() openAcknowledgements:sender];
}
- (void)windowWillClose:(NSNotification *)note
{
[self.window saveWindowStateForClass:self.class];
if ([self.delegate respondsToSelector:@selector(aboutDialogWillClose:)]) {
[self.delegate aboutDialogWillClose:self];
}
}
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Dialogs/TDCAddressBookSheet.m
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "NSObjectHelperPrivate.h"
#import "NSStringHelper.h"
#import "TLOLocalization.h"
#import "TVCValidatedTextField.h"
#import "TDCAddressBookSheetPrivate.h"
NS_ASSUME_NONNULL_BEGIN
@interface TDCAddressBookSheet ()
@property (nonatomic, strong) IRCAddressBookEntryMutable *config;
@property (nonatomic, assign) IRCAddressBookEntryType entryType;
@property (nonatomic, strong) IBOutlet NSButton *ignoreClientToClientProtocolCheck;
@property (nonatomic, strong) IBOutlet NSButton *ignoreFileTransferRequestsCheck;
@property (nonatomic, strong) IBOutlet NSButton *ignoreGeneralEventMessagesCheck;
@property (nonatomic, strong) IBOutlet NSButton *ignoreInlineMediaCheck;
@property (nonatomic, strong) IBOutlet NSButton *ignoreNoticeMessagesCheck;
@property (nonatomic, strong) IBOutlet NSButton *ignorePrivateMessageHighlightsCheck;
@property (nonatomic, strong) IBOutlet NSButton *ignorePrivateMessagesCheck;
@property (nonatomic, strong) IBOutlet NSButton *ignorePublicMessageHighlightsCheck;
@property (nonatomic, strong) IBOutlet NSButton *ignorePublicMessagesCheck;
@property (nonatomic, strong) IBOutlet NSButton *trackUserActivityCheck;
@property (nonatomic, strong) IBOutlet NSButton *ignoreEntrySaveButton;
@property (nonatomic, strong) IBOutlet NSButton *userTrackingEntrySaveButton;
@property (nonatomic, strong) IBOutlet TVCValidatedTextField *ignoreEntryHostmaskTextField;
@property (nonatomic, strong) IBOutlet TVCValidatedTextField *userTrackingEntryNicknameTextField;
@property (nonatomic, strong) IBOutlet NSWindow *ignoreEntryView;
@property (nonatomic, strong) IBOutlet NSWindow *userTrackingEntryView;
@end
@implementation TDCAddressBookSheet
- (instancetype)initWithEntryType:(IRCAddressBookEntryType)entryType
{
NSParameterAssert(entryType == IRCAddressBookEntryTypeIgnore ||
entryType == IRCAddressBookEntryTypeUserTracking);
if ((self = [super initWithWindow:nil])) {
if (entryType == IRCAddressBookEntryTypeIgnore) {
self.config = [IRCAddressBookEntryMutable newIgnoreEntry];
} else if (entryType == IRCAddressBookEntryTypeUserTracking) {
self.config = [IRCAddressBookEntryMutable newUserTrackingEntry];
}
self.entryType = entryType;
[self prepareInitialState];
[self loadConfig];
return self;
}
return nil;
}
- (instancetype)initWithConfig:(IRCAddressBookEntry *)config
{
NSParameterAssert(config != nil);
NSParameterAssert(config.entryType == IRCAddressBookEntryTypeIgnore ||
config.entryType == IRCAddressBookEntryTypeUserTracking);
if ((self = [super initWithWindow:nil])) {
self.config = [config mutableCopy];
self.entryType = config.entryType;
[self prepareInitialState];
[self loadConfig];
return self;
}
return nil;
}
- (void)prepareInitialState
{
[RZMainBundle() loadNibNamed:@"TDCAddressBookSheet" owner:self topLevelObjects:nil];
self.ignoreEntryHostmaskTextField.stringValueIsInvalidOnEmpty = YES;
self.ignoreEntryHostmaskTextField.stringValueUsesOnlyFirstToken = YES;
self.ignoreEntryHostmaskTextField.validationBlock = ^NSString *(NSString *currentValue) {
NSString *valueWithoutWildcard = [currentValue stringByReplacingOccurrencesOfString:@"*" withString:@"-"];
if (valueWithoutWildcard.isHostmask == NO) {
return TXTLS(@"TDCAddressBookSheet[csu-bv]");
}
return nil;
};
self.userTrackingEntryNicknameTextField.stringValueIsInvalidOnEmpty = YES;
self.userTrackingEntryNicknameTextField.stringValueUsesOnlyFirstToken = YES;
self.userTrackingEntryNicknameTextField.validationBlock = ^NSString *(NSString *currentValue) {
if (currentValue.isHostmaskNickname == NO) {
return TXTLS(@"CommonErrors[och-j5]");
}
return nil;
};
}
- (void)loadConfig
{
if (self.entryType == IRCAddressBookEntryTypeIgnore)
{
self.ignoreEntryHostmaskTextField.stringValue = self.config.hostmask;
self.ignoreClientToClientProtocolCheck.state = self.config.ignoreClientToClientProtocol;
self.ignoreFileTransferRequestsCheck.state = self.config.ignoreFileTransferRequests;
self.ignoreGeneralEventMessagesCheck.state = self.config.ignoreGeneralEventMessages;
self.ignoreInlineMediaCheck.state = self.config.ignoreInlineMedia;
self.ignoreNoticeMessagesCheck.state = self.config.ignoreNoticeMessages;
self.ignorePrivateMessageHighlightsCheck.state = self.config.ignorePrivateMessageHighlights;
self.ignorePrivateMessagesCheck.state = self.config.ignorePrivateMessages;
self.ignorePublicMessageHighlightsCheck.state = self.config.ignorePublicMessageHighlights;
self.ignorePublicMessagesCheck.state = self.config.ignorePublicMessages;
}
else if (self.entryType == IRCAddressBookEntryTypeUserTracking)
{
self.userTrackingEntryNicknameTextField.stringValue = self.config.hostmask;
self.trackUserActivityCheck.state = self.config.trackUserActivity;
}
}
- (void)start
{
if (self.entryType == IRCAddressBookEntryTypeIgnore)
{
self.sheet = self.ignoreEntryView;
[self.sheet makeFirstResponder:self.ignoreEntryHostmaskTextField];
}
else if (self.entryType == IRCAddressBookEntryTypeUserTracking)
{
self.sheet = self.userTrackingEntryView;
[self.sheet makeFirstResponder:self.userTrackingEntryNicknameTextField];
}
[self startSheet];
}
- (void)ok:(id)sender
{
if ([self okOrError] == NO) {
return;
}
if (self.entryType == IRCAddressBookEntryTypeIgnore)
{
self.config.hostmask = self.ignoreEntryHostmaskTextField.value;
self.config.ignoreClientToClientProtocol = (self.ignoreClientToClientProtocolCheck.state == NSControlStateValueOn);
self.config.ignoreFileTransferRequests = (self.ignoreFileTransferRequestsCheck.state == NSControlStateValueOn);
self.config.ignoreGeneralEventMessages = (self.ignoreGeneralEventMessagesCheck.state == NSControlStateValueOn);
self.config.ignoreInlineMedia = (self.ignoreInlineMediaCheck.state == NSControlStateValueOn);
self.config.ignoreNoticeMessages = (self.ignoreNoticeMessagesCheck.state == NSControlStateValueOn);
self.config.ignorePrivateMessageHighlights = (self.ignorePrivateMessageHighlightsCheck.state == NSControlStateValueOn);
self.config.ignorePrivateMessages = (self.ignorePrivateMessagesCheck.state == NSControlStateValueOn);
self.config.ignorePublicMessageHighlights = (self.ignorePublicMessageHighlightsCheck.state == NSControlStateValueOn);
self.config.ignorePublicMessages = (self.ignorePublicMessagesCheck.state == NSControlStateValueOn);
}
else if (self.entryType == IRCAddressBookEntryTypeUserTracking)
{
self.config.hostmask = self.userTrackingEntryNicknameTextField.value;
self.config.trackUserActivity = (self.trackUserActivityCheck.state == NSControlStateValueOn);
}
if ([self.delegate respondsToSelector:@selector(addressBookSheet:onOk:)]) {
[self.delegate addressBookSheet:self onOk:[self.config copy]];
}
[super ok:nil];
}
- (BOOL)okOrError
{
if (self.entryType == IRCAddressBookEntryTypeIgnore)
{
return [self okOrErrorForTextField:self.ignoreEntryHostmaskTextField];
}
else if (self.entryType == IRCAddressBookEntryTypeUserTracking)
{
return [self okOrErrorForTextField:self.userTrackingEntryNicknameTextField];
}
return NO;
}
#pragma mark -
#pragma mark NSWindow Delegate
- (void)windowWillClose:(NSNotification *)note
{
if ([self.delegate respondsToSelector:@selector(addressBookSheetWillClose:)]) {
[self.delegate addressBookSheetWillClose:self];
}
}
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Dialogs/TDCAlert.m
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "TLOLocalization.h"
#import "TPCPreferencesUserDefaults.h"
#import "TDCAlert.h"
NS_ASSUME_NONNULL_BEGIN
NSString * const TDCAlertSuppressionPrefix = @"Text Input Prompt Suppression -> ";
@interface TDCAlertContext : NSObject
@property (nonatomic, copy, nullable) NSString *suppressionKey;
@property (nonatomic, copy, nullable) TDCAlertCompletionBlock completionBlock;
@end
@implementation TDCAlert
#pragma mark -
#pragma mark Modal Alerts (Panel)
+ (BOOL)modalAlertWithMessage:(NSString *)bodyText
title:(NSString *)titleText
defaultButton:(NSString *)buttonDefault
alternateButton:(nullable NSString *)buttonAlternate
{
return
[self modalAlertWithMessage:bodyText
title:titleText
defaultButton:buttonDefault
alternateButton:buttonAlternate
suppressionKey:nil
suppressionText:nil
accessoryView:nil
suppressionResponse:NULL];
}
+ (BOOL)modalAlertWithMessage:(NSString *)bodyText
title:(NSString *)titleText
defaultButton:(NSString *)buttonDefault
alternateButton:(nullable NSString *)buttonAlternate
suppressionKey:(nullable NSString *)suppressKey
suppressionText:(nullable NSString *)suppressText
{
return
[self modalAlertWithMessage:bodyText
title:titleText
defaultButton:buttonDefault
alternateButton:buttonAlternate
suppressionKey:suppressKey
suppressionText:suppressText
accessoryView:nil
suppressionResponse:NULL];
}
+ (BOOL)modalAlertWithMessage:(NSString *)bodyText
title:(NSString *)titleText
defaultButton:(NSString *)buttonDefault
alternateButton:(nullable NSString *)buttonAlternate
suppressionKey:(nullable NSString *)suppressKey
suppressionText:(nullable NSString *)suppressText
accessoryView:(nullable NSView *)accessoryView
{
return
[self modalAlertWithMessage:bodyText
title:titleText
defaultButton:buttonDefault
alternateButton:buttonAlternate
suppressionKey:suppressKey
suppressionText:suppressText
accessoryView:accessoryView
suppressionResponse:NULL];
}
+ (BOOL)modalAlertWithMessage:(NSString *)bodyText
title:(NSString *)titleText
defaultButton:(NSString *)buttonDefault
alternateButton:(nullable NSString *)buttonAlternate
suppressionKey:(nullable NSString *)suppressKey
suppressionText:(nullable NSString *)suppressText
suppressionResponse:(nullable BOOL *)suppressionResponse
{
return
[self modalAlertWithMessage:bodyText
title:titleText
defaultButton:buttonDefault
alternateButton:buttonAlternate
suppressionKey:suppressKey
suppressionText:suppressText
accessoryView:nil
suppressionResponse:suppressionResponse];
}
+ (BOOL)modalAlertWithMessage:(NSString *)bodyText
title:(NSString *)titleText
defaultButton:(NSString *)buttonDefault
alternateButton:(nullable NSString *)buttonAlternate
suppressionKey:(nullable NSString *)suppressKey
suppressionText:(nullable NSString *)suppressText
accessoryView:(nullable NSView *)accessoryView
suppressionResponse:(nullable BOOL *)suppressionResponse
{
TDCAlertResponse response =
[self modalAlertWithMessage:bodyText
title:titleText
defaultButton:buttonDefault
alternateButton:buttonAlternate
otherButton:nil
suppressionKey:suppressKey
suppressionText:suppressText
accessoryView:nil
suppressionResponse:nil];
return (response == TDCAlertResponseDefault);
}
+ (TDCAlertResponse)modalAlertWithMessage:(NSString *)bodyText
title:(NSString *)titleText
defaultButton:(NSString *)buttonDefault
alternateButton:(nullable NSString *)buttonAlternate
otherButton:(nullable NSString *)buttonOther
{
return
[self modalAlertWithMessage:bodyText
title:titleText
defaultButton:buttonDefault
alternateButton:buttonAlternate
otherButton:buttonOther
suppressionKey:nil
suppressionText:nil
accessoryView:nil
suppressionResponse:nil];
}
+ (TDCAlertResponse)modalAlertWithMessage:(NSString *)bodyText
title:(NSString *)titleText
defaultButton:(NSString *)buttonDefault
alternateButton:(nullable NSString *)buttonAlternate
otherButton:(nullable NSString *)buttonOther
suppressionKey:(nullable NSString *)suppressKey
suppressionText:(nullable NSString *)suppressText
accessoryView:(nullable NSView *)accessoryView
suppressionResponse:(nullable BOOL *)suppressionResponse
{
NSParameterAssert(bodyText != nil);
NSParameterAssert(titleText != nil);
NSParameterAssert(buttonDefault != nil);
/* Require main thread */
if ([NSThread isMainThread] == NO) {
__block TDCAlertResponse result = TDCAlertResponseAlternate;
XRPerformBlockSynchronouslyOnQueue(dispatch_get_main_queue(), ^{
result =
[self modalAlertWithMessage:bodyText
title:titleText
defaultButton:buttonDefault
alternateButton:buttonAlternate
otherButton:buttonOther
suppressionKey:suppressKey
suppressionText:suppressText
accessoryView:accessoryView
suppressionResponse:suppressionResponse];
});
return result;
}
/* Prepare suppression */
if (suppressKey) {
suppressKey = [self suppressionKeyWithBase:suppressKey];
/* Exit if suppressed */
if ([RZUserDefaults() boolForKey:suppressKey]) {
return TDCAlertResponseDefault;
}
}
if (suppressKey && (suppressText == nil || suppressText.length == 0)) {
suppressText = TXTLS(@"Prompts[68u-z9]");
}
/* Construct alert */
NSAlert *alert = [NSAlert new];
alert.messageText = titleText;
alert.informativeText = bodyText;
[alert addButtonWithTitle:buttonDefault];
if (buttonAlternate) {
[alert addButtonWithTitle:buttonAlternate];
}
if (buttonOther) {
[alert addButtonWithTitle:buttonOther];
}
if (suppressKey || suppressText) {
alert.showsSuppressionButton = YES;
alert.suppressionButton.title = suppressText;
}
if (accessoryView) {
alert.accessoryView = accessoryView;
}
/* Pop alert */
NSModalResponse returnCode = [alert runModal];
TDCAlertResponse response = [self _convertResponseFromNSAlert:returnCode];
[self _finalizeAlert:alert
withResponse:response
completionBlock:nil
suppressionKey:suppressKey
suppressionResponse:suppressionResponse];
return response;
}
#pragma mark -
#pragma mark Non-blocking Alerts (Panel)
+ (TVCAlert *)alertWithMessage:(NSString *)bodyText
title:(NSString *)titleText
defaultButton:(NSString *)buttonDefault
alternateButton:(nullable NSString *)buttonAlternate
{
/* Will never return nil because no suppression. */
return (TVCAlert * _Nonnull)
[self alertWithMessage:bodyText
title:titleText
defaultButton:buttonDefault
alternateButton:buttonAlternate
otherButton:nil
suppressionKey:nil
suppressionText:nil
accessoryView:nil
completionBlock:nil];
}
+ (TVCAlert *)alertWithMessage:(NSString *)bodyText
title:(NSString *)titleText
defaultButton:(NSString *)buttonDefault
alternateButton:(nullable NSString *)buttonAlternate
otherButton:(nullable NSString *)buttonOther
{
return (TVCAlert * _Nonnull)
[self alertWithMessage:bodyText
title:titleText
defaultButton:buttonDefault
alternateButton:buttonAlternate
otherButton:buttonOther
suppressionKey:nil
suppressionText:nil
accessoryView:nil
completionBlock:nil];
}
+ (nullable TVCAlert *)alertWithMessage:(NSString *)bodyText
title:(NSString *)titleText
defaultButton:(NSString *)buttonDefault
alternateButton:(nullable NSString *)buttonAlternate
suppressionKey:(nullable NSString *)suppressKey
suppressionText:(nullable NSString *)suppressText
{
return
[self alertWithMessage:bodyText
title:titleText
defaultButton:buttonDefault
alternateButton:buttonAlternate
otherButton:nil
suppressionKey:suppressKey
suppressionText:suppressText
accessoryView:nil
completionBlock:nil];
}
+ (nullable TVCAlert *)alertWithMessage:(NSString *)bodyText
title:(NSString *)titleText
defaultButton:(NSString *)buttonDefault
alternateButton:(nullable NSString *)buttonAlternate
completionBlock:(nullable TDCAlertCompletionBlock)completionBlock
{
return
[self alertWithMessage:bodyText
title:titleText
defaultButton:buttonDefault
alternateButton:buttonAlternate
otherButton:nil
suppressionKey:nil
suppressionText:nil
accessoryView:nil
completionBlock:completionBlock];
}
+ (nullable TVCAlert *)alertWithMessage:(NSString *)bodyText
title:(NSString *)titleText
defaultButton:(NSString *)buttonDefault
alternateButton:(nullable NSString *)buttonAlternate
otherButton:(nullable NSString *)buttonOther
completionBlock:(nullable TDCAlertCompletionBlock)completionBlock
{
return
[self alertWithMessage:bodyText
title:titleText
defaultButton:buttonDefault
alternateButton:buttonAlternate
otherButton:buttonOther
suppressionKey:nil
suppressionText:nil
accessoryView:nil
completionBlock:completionBlock];
}
+ (nullable TVCAlert *)alertWithMessage:(NSString *)bodyText
title:(NSString *)titleText
defaultButton:(NSString *)buttonDefault
alternateButton:(nullable NSString *)buttonAlternate
suppressionKey:(nullable NSString *)suppressKey
suppressionText:(nullable NSString *)suppressText
completionBlock:(nullable TDCAlertCompletionBlock)completionBlock
{
return
[self alertWithMessage:bodyText
title:titleText
defaultButton:buttonDefault
alternateButton:buttonAlternate
otherButton:nil
suppressionKey:suppressKey
suppressionText:suppressText
accessoryView:nil
completionBlock:completionBlock];
}
+ (nullable TVCAlert *)alertWithMessage:(NSString *)bodyText
title:(NSString *)titleText
defaultButton:(NSString *)buttonDefault
alternateButton:(nullable NSString *)buttonAlternate
otherButton:(nullable NSString *)buttonOther
suppressionKey:(nullable NSString *)suppressKey
suppressionText:(nullable NSString *)suppressText
completionBlock:(nullable TDCAlertCompletionBlock)completionBlock
{
return
[self alertWithMessage:bodyText
title:titleText
defaultButton:buttonDefault
alternateButton:buttonAlternate
otherButton:buttonOther
suppressionKey:suppressKey
suppressionText:suppressText
accessoryView:nil
completionBlock:completionBlock];
}
+ (nullable TVCAlert *)alertWithMessage:(NSString *)bodyText
title:(NSString *)titleText
defaultButton:(NSString *)buttonDefault
alternateButton:(nullable NSString *)buttonAlternate
suppressionKey:(nullable NSString *)suppressKey
suppressionText:(nullable NSString *)suppressText
accessoryView:(nullable NSView *)accessoryView
completionBlock:(nullable TDCAlertCompletionBlock)completionBlock
{
return
[self alertWithMessage:bodyText
title:titleText
defaultButton:buttonDefault
alternateButton:buttonAlternate
otherButton:nil
suppressionKey:suppressKey
suppressionText:suppressText
accessoryView:accessoryView
completionBlock:completionBlock];
}
+ (nullable TVCAlert *)alertWithMessage:(NSString *)bodyText
title:(NSString *)titleText
defaultButton:(NSString *)buttonDefault
alternateButton:(nullable NSString *)buttonAlternate
otherButton:(nullable NSString *)buttonOther
suppressionKey:(nullable NSString *)suppressKey
suppressionText:(nullable NSString *)suppressText
accessoryView:(nullable NSView *)accessoryView
completionBlock:(nullable TDCAlertCompletionBlock)completionBlock
{
NSParameterAssert(bodyText != nil);
NSParameterAssert(titleText != nil);
NSParameterAssert(buttonDefault != nil);
/* Require main thread */
if ([NSThread isMainThread] == NO) {
__block TVCAlert *alert = nil;
XRPerformBlockSynchronouslyOnQueue(dispatch_get_main_queue(), ^{
alert =
[self alertWithMessage:bodyText
title:titleText
defaultButton:buttonDefault
alternateButton:buttonAlternate
suppressionKey:suppressKey
suppressionText:suppressText
accessoryView:accessoryView
completionBlock:completionBlock];
});
return alert;
}
/* Prepare suppression */
if (suppressKey) {
suppressKey = [self suppressionKeyWithBase:suppressKey];
/* Exit if suppressed */
if ([RZUserDefaults() boolForKey:suppressKey]) {
if (completionBlock) {
completionBlock(TDCAlertResponseDefault, YES, nil);
}
return nil;
}
}
if (suppressKey && (suppressText == nil || suppressText.length == 0)) {
suppressText = TXTLS(@"Prompts[68u-z9]");
}
/* Construct alert */
TVCAlert *alert = [TVCAlert new];
alert.messageText = titleText;
alert.informativeText = bodyText;
[alert setTitle:buttonDefault forButton:TVCAlertResponseButtonFirst];
if (buttonAlternate) {
[alert setTitle:buttonAlternate forButton:TVCAlertResponseButtonSecond];
}
if (buttonOther) {
[alert setTitle:buttonOther forButton:TVCAlertResponseButtonThird];
}
if (suppressKey || suppressText) {
alert.showsSuppressionButton = YES;
alert.suppressionButton.title = suppressText;
}
if (accessoryView) {
alert.accessoryView = accessoryView;
}
/* Pop alert */
[alert showAlertWithCompletionBlock:^(TVCAlert *sender, TVCAlertResponseButton buttonClicked)
{
[self _finalizeAlert:alert
withResponse:[self _convertResponseFromTVCAlert:buttonClicked]
completionBlock:completionBlock
suppressionKey:suppressKey
suppressionResponse:NULL];
}];
return alert;
}
#pragma mark -
#pragma mark Non-blocking Alerts (Sheet)
+ (void)alertSheetWithWindow:(NSWindow *)window
body:(NSString *)bodyText
title:(NSString *)titleText
defaultButton:(NSString *)buttonDefault
alternateButton:(nullable NSString *)buttonAlternate
otherButton:(nullable NSString *)buttonOther
{
[self alertSheetWithWindow:window
body:bodyText
title:titleText
defaultButton:buttonDefault
alternateButton:buttonAlternate
otherButton:buttonOther
suppressionKey:nil
suppressionText:nil
accessoryView:nil
completionBlock:nil];
}
+ (void)alertSheetWithWindow:(NSWindow *)window
body:(NSString *)bodyText
title:(NSString *)titleText
defaultButton:(NSString *)buttonDefault
alternateButton:(nullable NSString *)buttonAlternate
otherButton:(nullable NSString *)buttonOther
completionBlock:(nullable TDCAlertCompletionBlock)completionBlock
{
[self alertSheetWithWindow:window
body:bodyText
title:titleText
defaultButton:buttonDefault
alternateButton:buttonAlternate
otherButton:buttonOther
suppressionKey:nil
suppressionText:nil
accessoryView:nil
completionBlock:completionBlock];
}
+ (void)alertSheetWithWindow:(NSWindow *)window
body:(NSString *)bodyText
title:(NSString *)titleText
defaultButton:(NSString *)buttonDefault
alternateButton:(nullable NSString *)buttonAlternate
otherButton:(nullable NSString *)buttonOther
accessoryView:(nullable NSView *)accessoryView
completionBlock:(nullable TDCAlertCompletionBlock)completionBlock
{
[self alertSheetWithWindow:window
body:bodyText
title:titleText
defaultButton:buttonDefault
alternateButton:buttonAlternate
otherButton:buttonOther
suppressionKey:nil
suppressionText:nil
accessoryView:accessoryView
completionBlock:completionBlock];
}
+ (void)alertSheetWithWindow:(NSWindow *)window
body:(NSString *)bodyText
title:(NSString *)titleText
defaultButton:(NSString *)buttonDefault
alternateButton:(nullable NSString *)buttonAlternate
otherButton:(nullable NSString *)buttonOther
suppressionKey:(nullable NSString *)suppressKey
suppressionText:(nullable NSString *)suppressText
completionBlock:(nullable TDCAlertCompletionBlock)completionBlock
{
[self alertSheetWithWindow:window
body:bodyText
title:titleText
defaultButton:buttonDefault
alternateButton:buttonAlternate
otherButton:buttonOther
suppressionKey:suppressKey
suppressionText:suppressText
accessoryView:nil
completionBlock:completionBlock];
}
+ (void)alertSheetWithWindow:(NSWindow *)window
body:(NSString *)bodyText
title:(NSString *)titleText
defaultButton:(NSString *)buttonDefault
alternateButton:(nullable NSString *)buttonAlternate
otherButton:(nullable NSString *)buttonOther
suppressionKey:(nullable NSString *)suppressKey
suppressionText:(nullable NSString *)suppressText
accessoryView:(nullable NSView *)accessoryView
completionBlock:(nullable TDCAlertCompletionBlock)completionBlock
{
NSParameterAssert(window != nil);
NSParameterAssert(bodyText != nil);
NSParameterAssert(titleText != nil);
NSParameterAssert(buttonDefault != nil);
/* Require main thread */
if ([NSThread isMainThread] == NO) {
XRPerformBlockSynchronouslyOnQueue(dispatch_get_main_queue(), ^{
[self alertSheetWithWindow:window
body:bodyText
title:titleText
defaultButton:buttonDefault
alternateButton:buttonAlternate
otherButton:buttonOther
suppressionKey:suppressKey
suppressionText:suppressText
accessoryView:accessoryView
completionBlock:completionBlock];
});
return;
}
/* Prepare suppression */
if (suppressKey) {
suppressKey = [self suppressionKeyWithBase:suppressKey];
/* Exit if suppressed */
if ([RZUserDefaults() boolForKey:suppressKey]) {
if (completionBlock) {
completionBlock(TDCAlertResponseDefault, YES, nil);
}
return;
}
}
if (suppressKey && (suppressText == nil || suppressText.length == 0)) {
suppressText = TXTLS(@"Prompts[68u-z9]");
}
/* Construct alert */
NSAlert *alert = [NSAlert new];
alert.alertStyle = NSAlertStyleInformational;
alert.messageText = titleText;
alert.informativeText = bodyText;
[alert addButtonWithTitle:buttonDefault];
if (buttonAlternate) {
[alert addButtonWithTitle:buttonAlternate];
}
if (buttonOther) {
[alert addButtonWithTitle:buttonOther];
}
if (suppressKey || suppressText) {
alert.showsSuppressionButton = YES;
alert.suppressionButton.title = suppressText;
}
if (accessoryView) {
alert.accessoryView = accessoryView;
}
/* Construct alert context */
TDCAlertContext *context = [TDCAlertContext new];
context.suppressionKey = suppressKey;
context.completionBlock = completionBlock;
/* Pop alert */
[alert beginSheetModalForWindow:window completionHandler:^(NSModalResponse returnCode) {
[self _alertSheetResponseCallback:alert returnCode:returnCode contextInfo:context];
}];
}
+ (void)_alertSheetResponseCallback:(NSAlert *)alert returnCode:(NSInteger)returnCode contextInfo:(TDCAlertContext *)context
{
NSString *suppressionKey = context.suppressionKey;
TDCAlertCompletionBlock completionBlock = context.completionBlock;
[self _finalizeAlert:alert
withResponse:[self _convertResponseFromNSAlert:returnCode]
completionBlock:completionBlock
suppressionKey:suppressionKey
suppressionResponse:NULL];
}
#pragma mark -
#pragma mark Utilities
+ (NSString *)suppressionKeyWithBase:(NSString *)base
{
NSParameterAssert(base != nil);
if ([base hasPrefix:TDCAlertSuppressionPrefix]) {
return base;
}
return [TDCAlertSuppressionPrefix stringByAppendingString:base];
}
+ (void)_finalizeAlert:(nullable id)underlyingAlert
withResponse:(TDCAlertResponse)response
completionBlock:(nullable TDCAlertCompletionBlock)completionBlock
suppressionKey:(nullable NSString *)suppressionKey
suppressionResponse:(nullable BOOL *)suppressionResponse
{
BOOL suppressed = [self _recordSuppressionForButton:[underlyingAlert suppressionButton] withKey:suppressionKey];
if ( suppressionResponse) {
*suppressionResponse = suppressed;
}
if (completionBlock) {
completionBlock(response, suppressed, underlyingAlert);
}
}
+ (BOOL)_recordSuppressionForButton:(nullable NSButton *)suppressionButton withKey:(nullable NSString *)suppressionKey
{
/* There are some times when we use suppression text field
to give user option that doesn't mean to suppress the
prompt next time. We therefore only return NO for both
arguments missing and not just one. */
if (suppressionButton == nil && suppressionKey == nil) {
return NO;
}
BOOL suppressed = (suppressionButton.state == NSControlStateValueOn);
if (suppressed && suppressionKey != nil) {
[RZUserDefaults() setBool:YES forKey:suppressionKey];
}
return suppressed;
}
+ (TDCAlertResponse)_convertResponseFromNSAlert:(NSUInteger)response
{
switch (response) {
case NSAlertSecondButtonReturn:
{
return TDCAlertResponseAlternate;
}
case NSAlertThirdButtonReturn:
{
return TDCAlertResponseOther;
}
default:
{
return TDCAlertResponseDefault;
}
}
}
+ (TDCAlertResponse)_convertResponseFromTVCAlert:(TVCAlertResponseButton)response
{
switch (response) {
case TVCAlertResponseButtonSecond:
{
return TDCAlertResponseAlternate;
}
case TVCAlertResponseButtonThird:
{
return TDCAlertResponseOther;
}
default:
{
return TDCAlertResponseDefault;
}
}
}
@end
#pragma mark -
@implementation TDCAlertContext
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Dialogs/TDCChannelBanListSheet.m
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "NSObjectHelperPrivate.h"
#import "TXGlobalModels.h"
#import "TLOLocalization.h"
#import "IRCClient.h"
#import "IRCChannel.h"
#import "IRCISupportInfo.h"
#import "TVCBasicTableView.h"
#import "TDCChannelBanListSheetPrivate.h"
NS_ASSUME_NONNULL_BEGIN
@interface TDCChannelBanListSheetEntry : NSObject
@property (nonatomic, copy) NSString *entryMask;
@property (nonatomic, copy) NSString *entryAuthor;
@property (readonly, copy) NSString *entryCreationDateString;
@property (nonatomic, copy, nullable) NSDate *entryCreationDate;
@end
@interface TDCChannelBanListSheet ()
@property (nonatomic, strong, readwrite) IRCClient *client;
@property (nonatomic, strong, readwrite) IRCChannel *channel;
@property (nonatomic, copy, readwrite) NSString *clientId;
@property (nonatomic, copy, readwrite) NSString *channelId;
@property (nonatomic, assign, readwrite) TDCChannelBanListSheetEntryType entryType;
@property (nonatomic, copy, readwrite, nullable) NSArray *listOfChanges;
@property (nonatomic, weak) IBOutlet NSTextField *headerTitleTextField;
@property (nonatomic, weak) IBOutlet TVCBasicTableView *entryTable;
@property (nonatomic, strong) IBOutlet NSArrayController *entryTableController;
- (IBAction)onUpdate:(id)sender;
- (IBAction)onRemoveEntry:(id)sender;
@end
@implementation TDCChannelBanListSheet
- (nullable instancetype)initWithEntryType:(TDCChannelBanListSheetEntryType)entryType inChannel:(IRCChannel *)channel
{
NSParameterAssert(channel != nil);
if ([self.class channel:channel supportsEntryType:entryType] == NO) {
return nil;
}
if ((self = [super initWithWindow:nil])) {
self.entryType = entryType;
self.client = channel.associatedClient;
self.clientId = channel.associatedClient.uniqueIdentifier;
self.channel = channel;
self.channelId = channel.uniqueIdentifier;
[self prepareInitialState];
return self;
}
return nil;
}
- (void)prepareInitialState
{
[RZMainBundle() loadNibNamed:@"TDCChannelBanListSheet" owner:self topLevelObjects:nil];
self.entryTable.sortDescriptors = @[
[NSSortDescriptor sortDescriptorWithKey:@"entryCreationDate" ascending:NO selector:@selector(compare:)]
];
NSString *headerTitle = nil;
if (self.entryType == TDCChannelBanListSheetEntryTypeBan) {
headerTitle = TXTLS(@"TDCChannelBanListSheet[rhc-ke]", self.channel.name);
} else if (self.entryType == TDCChannelBanListSheetEntryTypeBanException) {
headerTitle = TXTLS(@"TDCChannelBanListSheet[gbi-wn]", self.channel.name);
} else if (self.entryType == TDCChannelBanListSheetEntryTypeInviteException) {
headerTitle = TXTLS(@"TDCChannelBanListSheet[ylc-6e]", self.channel.name);
} else if (self.entryType == TDCChannelBanListSheetEntryTypeQuiet) {
headerTitle = TXTLS(@"TDCChannelBanListSheet[g4r-t6]", self.channel.name);
}
self.headerTitleTextField.stringValue = headerTitle;
}
- (void)start
{
[self startSheet];
}
- (void)clear
{
self.entryTableController.content = nil;
}
- (void)addEntry:(NSString *)entryMask setBy:(nullable NSString *)entryAuthor creationDate:(nullable NSDate *)entryCreationDate
{
NSParameterAssert(entryMask != nil);
if (entryAuthor == nil) {
entryAuthor = TXTLS(@"BasicLanguage[vbl-xi]"); // "Unknown"
}
TDCChannelBanListSheetEntry *newEntry = [TDCChannelBanListSheetEntry new];
newEntry.entryMask = entryMask;
newEntry.entryAuthor = entryAuthor;
newEntry.entryCreationDate = entryCreationDate;
[self willChangeValueForKey:@"entryCount"];
[self.entryTableController addObject:newEntry];
[self didChangeValueForKey:@"entryCount"];
}
- (NSNumber *)entryCount
{
return @([self.entryTableController.arrangedObjects count]);
}
#pragma mark -
#pragma mark Actions
- (void)onUpdate:(id)sender
{
[self clear];
if ([self.delegate respondsToSelector:@selector(channelBanListSheetOnUpdate:)]) {
[self.delegate channelBanListSheetOnUpdate:self];
}
}
- (void)onRemoveEntry:(id)sender
{
NSIndexSet *selectedRows = self.entryTable.selectedRowIndexes;
NSMutableArray *selectedEntries = [NSMutableArray arrayWithCapacity:selectedRows.count];
[selectedRows enumerateIndexesUsingBlock:^(NSUInteger index, BOOL *stop) {
TDCChannelBanListSheetEntry *entryItem = self.entryTableController.arrangedObjects[index];
[selectedEntries addObject:entryItem.entryMask];
}];
self.listOfChanges =
[self.client compileListOfModeChangesForModeSymbol:self.modeSymbol
modeIsSet:NO
modeParameters:selectedEntries];
[super cancel:nil];
}
#pragma mark -
#pragma mark Utilities
+ (BOOL)channel:(IRCChannel *)channel supportsEntryType:(TDCChannelBanListSheetEntryType)entryType
{
return [channel.associatedClient.supportInfo isListSupported:(IRCISupportInfoListType)entryType];
}
- (NSString *)modeSymbol
{
/* -modeSymbolForList: is nullable but because we only allow this class to be
created if the mode is already supported, then we can advertise it here as non-nil */
return [self.client.supportInfo modeSymbolForList:(IRCISupportInfoListType)self.entryType];
}
#pragma mark -
#pragma mark NSWindow Delegate
- (void)windowWillClose:(NSNotification *)note
{
if ([self.delegate respondsToSelector:@selector(channelBanListSheetWillClose:)]) {
[self.delegate channelBanListSheetWillClose:self];
}
}
@end
#pragma mark -
@implementation TDCChannelBanListSheetEntry
- (NSString *)entryCreationDateString
{
NSDate *entryCreationDate = self.entryCreationDate;
if (entryCreationDate == nil) {
return TXTLS(@"BasicLanguage[vbl-xi]"); // "Unknown"
}
return TXFormatDateLongStyle(entryCreationDate, YES);
}
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Dialogs/TDCChannelInviteSheet.m
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2008 - 2010 Satoshi Nakagawa
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "IRCClient.h"
#import "TLOLocalization.h"
#import "TDCChannelInviteSheetPrivate.h"
NS_ASSUME_NONNULL_BEGIN
@interface TDCChannelInviteSheet ()
@property (nonatomic, strong, readwrite) IRCClient *client;
@property (nonatomic, copy, readwrite) NSString *clientId;
@property (nonatomic, copy, readwrite) NSArray *nicknames;
@property (nonatomic, weak) IBOutlet NSTextField *headerTitleTextField;
@property (nonatomic, weak) IBOutlet NSPopUpButton *channelListPopup;
@end
@implementation TDCChannelInviteSheet
- (instancetype)initWithNicknames:(NSArray *)nicknames onClient:(IRCClient *)client
{
NSParameterAssert(nicknames != nil);
NSParameterAssert(client != nil);
if ((self = [super initWithWindow:nil])) {
self.nicknames = nicknames;
self.client = client;
self.clientId = client.uniqueIdentifier;
[self prepareInitialState];
return self;
}
return nil;
}
- (void)prepareInitialState
{
[RZMainBundle() loadNibNamed:@"TDCChannelInviteSheet" owner:self topLevelObjects:nil];
NSUInteger nicknameCount = self.nicknames.count;
NSString *headerTitle = nil;
if (nicknameCount == 1) {
headerTitle = self.nicknames[0];
} else if (nicknameCount == 2) {
headerTitle = TXTLS(@"TDCChannelInviteSheet[7i1-ds]", self.nicknames[0], self.nicknames[1]);
} else {
headerTitle = TXTLS(@"TDCChannelInviteSheet[c8p-sb]", nicknameCount);
}
self.headerTitleTextField.stringValue = TXTLS(@"TDCChannelInviteSheet[0lg-er]", headerTitle);
}
- (void)startWithChannels:(NSArray *)channels
{
NSParameterAssert(channels != nil);
for (NSString *channel in channels) {
[self.channelListPopup addItemWithTitle:channel];
}
[self startSheet];
}
- (void)ok:(id)sender
{
if ([self.delegate respondsToSelector:@selector(channelInviteSheet:onSelectChannel:)]) {
NSString *channelName = self.channelListPopup.titleOfSelectedItem;
[self.delegate channelInviteSheet:self onSelectChannel:channelName];
}
[super ok:nil];
}
#pragma mark -
#pragma mark NSWindow Delegate
- (void)windowWillClose:(NSNotification *)note
{
if ([self.delegate respondsToSelector:@selector(channelInviteSheetWillClose:)]) {
[self.delegate channelInviteSheetWillClose:self];
}
}
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Dialogs/TDCChannelModifyModesSheet.m
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2008 - 2010 Satoshi Nakagawa
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "NSObjectHelperPrivate.h"
#import "TLOLocalization.h"
#import "IRCClient.h"
#import "IRCChannel.h"
#import "IRCChannelMode.h"
#import "IRCISupportInfo.h"
#import "IRCModeInfo.h"
#import "TDCAlert.h"
#import "TDCChannelModifyModesSheetPrivate.h"
NS_ASSUME_NONNULL_BEGIN
@interface TDCChannelModifyModesSheet ()
@property (nonatomic, strong, readwrite) IRCClient *client;
@property (nonatomic, strong, readwrite) IRCChannel *channel;
@property (nonatomic, copy, readwrite) NSString *clientId;
@property (nonatomic, copy, readwrite) NSString *channelId;
@property (nonatomic, strong) IRCChannelModeContainer *modes;
@property (nonatomic, weak) IBOutlet NSButton *sCheck;
@property (nonatomic, weak) IBOutlet NSButton *pCheck;
@property (nonatomic, weak) IBOutlet NSButton *nCheck;
@property (nonatomic, weak) IBOutlet NSButton *tCheck;
@property (nonatomic, weak) IBOutlet NSButton *iCheck;
@property (nonatomic, weak) IBOutlet NSButton *mCheck;
@property (nonatomic, weak) IBOutlet NSButton *kCheck;
@property (nonatomic, weak) IBOutlet NSButton *lCheck;
@property (nonatomic, weak) IBOutlet NSTextField *kText;
@property (nonatomic, weak) IBOutlet NSTextField *lText;
@property (nonatomic, copy) NSString *channelUserLimitMode;
@property (nonatomic, assign) BOOL secretKeyLengthAlertDisplayed;
- (IBAction)onChangeCheck:(id)sender;
@end
@implementation TDCChannelModifyModesSheet
- (instancetype)initWithChannel:(IRCChannel *)channel
{
NSParameterAssert(channel != nil);
if ((self = [super initWithWindow:nil])) {
self.client = channel.associatedClient;
self.clientId = channel.associatedClient.uniqueIdentifier;
self.channel = channel;
self.channelId = channel.uniqueIdentifier;
self.modes = [channel.modeInfo.modes copy];
[self prepareInitialState];
[self loadConfig];
return self;
}
return nil;
}
- (void)prepareInitialState
{
[RZMainBundle() loadNibNamed:@"TDCChannelModifyModesSheet" owner:self topLevelObjects:nil];
}
- (void)loadConfig
{
self.iCheck.state = [self.modes modeInfoFor:@"i"].modeIsSet;
self.mCheck.state = [self.modes modeInfoFor:@"m"].modeIsSet;
self.nCheck.state = [self.modes modeInfoFor:@"n"].modeIsSet;
self.pCheck.state = [self.modes modeInfoFor:@"p"].modeIsSet;
self.sCheck.state = [self.modes modeInfoFor:@"s"].modeIsSet;
self.tCheck.state = [self.modes modeInfoFor:@"t"].modeIsSet;
IRCModeInfo *kModeInfo = [self.modes modeInfoFor:@"k"];
self.kCheck.state = kModeInfo.modeIsSet;
if (kModeInfo.modeIsSet) {
self.kText.stringValue = kModeInfo.modeParameter;
}
IRCModeInfo *lModeInfo = [self.modes modeInfoFor:@"l"];
self.lCheck.state = lModeInfo.modeIsSet;
if (lModeInfo.modeIsSet) {
self.channelUserLimitMode = lModeInfo.modeParameter; // Set to local property for validation
}
[self updateTextFields];
}
- (void)start
{
[self startSheet];
}
- (BOOL)validateValue:(inout id *)value forKey:(NSString *)key error:(out NSError **)outError
{
if ([key isEqualToString:@"channelUserLimitMode"]) {
NSInteger valueInteger = [*value integerValue];
if (valueInteger < 0) {
*value = [NSString stringWithInteger:0];
} else if (valueInteger > 99999) {
*value = [NSString stringWithInteger:99999];
}
}
return YES;
}
- (void)updateTextFields
{
self.kText.enabled = (self.kCheck.state == NSControlStateValueOn);
self.lText.enabled = (self.lCheck.state == NSControlStateValueOn);
}
- (void)onChangeCheck:(id)sender
{
[self updateTextFields];
if (self.sCheck.state == NSControlStateValueOn &&
self.pCheck.state == NSControlStateValueOn)
{
if (sender == self.sCheck) {
self.pCheck.state = NSControlStateValueOff;
} else {
self.sCheck.state = NSControlStateValueOff;
}
}
}
- (void)controlTextDidChange:(NSNotification *)aNotification
{
if (aNotification.object == self.kText) {
[self updateSecretKeyLengthAlert];
}
}
- (void)updateSecretKeyLengthAlert
{
NSUInteger maximumKeyLength = self.client.supportInfo.maximumKeyLength;
if (maximumKeyLength == 0) {
return;
}
NSUInteger currentKeyLength = self.kText.stringValue.length;
if (currentKeyLength <= maximumKeyLength) {
return;
}
if (self.secretKeyLengthAlertDisplayed == NO) {
self.secretKeyLengthAlertDisplayed = YES;
} else {
return;
}
[TDCAlert alertSheetWithWindow:self.sheet
body:TXTLS(@"TDCChannelModifyModesSheet[lir-ra]")
title:TXTLS(@"TDCChannelModifyModesSheet[7m9-39]", self.client.networkNameAlt, maximumKeyLength)
defaultButton:TXTLS(@"Prompts[c7s-dq]")
alternateButton:nil
otherButton:nil
suppressionKey:@"maximum_secret_key_length"
suppressionText:nil
completionBlock:nil];
}
- (void)ok:(id)sender
{
[self.modes changeMode:@"i"
modeIsSet:(self.iCheck.state == NSControlStateValueOn)];
[self.modes changeMode:@"m"
modeIsSet:(self.mCheck.state == NSControlStateValueOn)];
[self.modes changeMode:@"n"
modeIsSet:(self.nCheck.state == NSControlStateValueOn)];
[self.modes changeMode:@"p"
modeIsSet:(self.pCheck.state == NSControlStateValueOn)];
[self.modes changeMode:@"s"
modeIsSet:(self.sCheck.state == NSControlStateValueOn)];
[self.modes changeMode:@"t"
modeIsSet:(self.tCheck.state == NSControlStateValueOn)];
[self.modes changeMode:@"k"
modeIsSet:(self.kCheck.state == NSControlStateValueOn)
modeParameter:self.kText.stringValue];
[self.modes changeMode:@"l"
modeIsSet:(self.lCheck.state == NSControlStateValueOn)
modeParameter:self.lText.stringValue];
if ([self.delegate respondsToSelector:@selector(channelModifyModesSheet:onOk:)]) {
[self.delegate channelModifyModesSheet:self onOk:self.modes];
}
[super ok:nil];
}
#pragma mark -
#pragma mark NSWindow Delegate
- (void)windowWillClose:(NSNotification *)note
{
if ([self.delegate respondsToSelector:@selector(channelModifyModesSheetWillClose:)]) {
[self.delegate channelModifyModesSheetWillClose:self];
}
}
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Dialogs/TDCChannelModifyTopicSheet.m
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2008 - 2010 Satoshi Nakagawa
* Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "NSObjectHelperPrivate.h"
#import "TLOLocalization.h"
#import "IRCClient.h"
#import "IRCChannel.h"
#import "IRCISupportInfo.h"
#import "TVCTextViewWithIRCFormatterPrivate.h"
#import "TDCAlert.h"
#import "TDCChannelModifyTopicSheetPrivate.h"
NS_ASSUME_NONNULL_BEGIN
@interface TDCChannelModifyTopicSheet ()
@property (nonatomic, strong, readwrite) IRCClient *client;
@property (nonatomic, strong, readwrite) IRCChannel *channel;
@property (nonatomic, copy, readwrite) NSString *clientId;
@property (nonatomic, copy, readwrite) NSString *channelId;
@property (nonatomic, weak) IBOutlet NSTextField *headerTitleTextField;
@property (nonatomic, strong) IBOutlet TVCTextViewWithIRCFormatter *topicValueTextField;
@property (nonatomic, assign) BOOL topicLengthAlertDisplayed;
@end
@implementation TDCChannelModifyTopicSheet
- (instancetype)initWithChannel:(IRCChannel *)channel
{
NSParameterAssert(channel != nil);
if ((self = [super initWithWindow:nil])) {
self.client = channel.associatedClient;
self.clientId = channel.associatedClient.uniqueIdentifier;
self.channel = channel;
self.channelId = channel.uniqueIdentifier;
[self prepareInitialState];
return self;
}
return nil;
}
- (void)prepareInitialState
{
[RZMainBundle() loadNibNamed:@"TDCChannelModifyTopicSheet" owner:self topLevelObjects:nil];
NSString *headerTitle = [NSString stringWithFormat:self.headerTitleTextField.stringValue, self.channel.name];
self.headerTitleTextField.stringValue = headerTitle;
self.topicValueTextField.preferredFont = [NSFont systemFontOfSize:13.0];
self.topicValueTextField.preferredFontColor = [NSColor textColor];
NSString *topic = self.channel.topic;
if (topic) {
self.topicValueTextField.stringValueWithIRCFormatting = topic;
}
}
- (void)start
{
[self startSheet];
}
- (void)textDidChange:(NSNotification *)aNotification
{
[self.topicValueTextField textDidChange:aNotification];
[self updateTopicLengthAlert];
}
- (void)updateTopicLengthAlert
{
NSUInteger maximumTopicLength = self.client.supportInfo.maximumTopicLength;
if (maximumTopicLength == 0) {
return;
}
NSUInteger currentTopicLength = self.topicValueTextField.stringLength;
if (currentTopicLength <= maximumTopicLength) {
return;
}
if (self.topicLengthAlertDisplayed == NO) {
self.topicLengthAlertDisplayed = YES;
} else {
return;
}
[TDCAlert alertSheetWithWindow:self.sheet
body:TXTLS(@"TDCChannelModifyTopicSheet[zm4-cr]")
title:TXTLS(@"TDCChannelModifyTopicSheet[27l-qx]", self.client.networkNameAlt, maximumTopicLength)
defaultButton:TXTLS(@"Prompts[c7s-dq]")
alternateButton:nil
otherButton:nil
suppressionKey:@"maximum_topic_length"
suppressionText:nil
completionBlock:nil];
}
- (BOOL)textView:(NSTextView *)aTextView doCommandBySelector:(SEL)aSelector
{
if (aSelector == @selector(insertNewline:)) {
[self ok:nil];
return YES;
} else if (aSelector == @selector(insertNewlineIgnoringFieldEditor:) ) {
/* Do not allow a new line to be inserted using Option + Enter */
return YES;
}
return NO;
}
- (void)ok:(id)sender
{
if ([self.delegate respondsToSelector:@selector(channelModifyTopicSheet:onOk:)]) {
NSString *formattedTopic = self.topicValueTextField.stringValueWithIRCFormatting;
NSString *topicWithoutNewlines = [formattedTopic stringByReplacingOccurrencesOfString:@"\n"
withString:@" "];
[self.delegate channelModifyTopicSheet:self onOk:topicWithoutNewlines];
}
[super ok:nil];
}
#pragma mark -
#pragma mark NSWindow Delegate
- (void)windowWillClose:(NSNotification *)note
{
if ([self.delegate respondsToSelector:@selector(channelModifyTopicSheetWillClose:)]) {
[self.delegate channelModifyTopicSheetWillClose:self];
}
}
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Dialogs/TDCChannelPropertiesNotificationConfiguration.m
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "IRCChannelConfig.h"
#import "TDCChannelPropertiesSheetInternal.h"
#import "TDCChannelPropertiesNotificationConfigurationPrivate.h"
NS_ASSUME_NONNULL_BEGIN
@interface TDCChannelPropertiesNotificationConfiguration ()
@property (nonatomic, weak) TDCChannelPropertiesSheet *sheet;
@property (readonly) IRCChannelConfigMutable *config;
@end
@implementation TDCChannelPropertiesNotificationConfiguration
- (instancetype)initWithEventType:(TXNotificationType)aEventType inSheet:(TDCChannelPropertiesSheet *)sheet
{
NSParameterAssert(sheet != nil);
if ((self = [super initWithEventType:aEventType])) {
self.sheet = sheet;
return self;
}
return nil;
}
- (IRCChannelConfigMutable *)config
{
return self.sheet.config;
}
- (nullable NSString *)alertSound
{
return [self.config soundForEvent:self.eventType];
}
- (void)setAlertSound:(nullable NSString *)alertSound
{
[self.config setSound:alertSound forEvent:self.eventType];
}
- (NSUInteger)pushNotification
{
return [self.config notificationEnabledForEvent:self.eventType];
}
- (void)setPushNotification:(NSUInteger)pushNotification
{
[self.config setNotificationEnabled:pushNotification forEvent:self.eventType];
}
- (NSUInteger)speakEvent
{
return [self.config speakEvent:self.eventType];
}
- (void)setSpeakEvent:(NSUInteger)speakEvent
{
[self.config setEventIsSpoken:speakEvent forEvent:self.eventType];
}
- (NSUInteger)disabledWhileAway
{
return [self.config disabledWhileAwayForEvent:self.eventType];
}
- (void)setDisabledWhileAway:(NSUInteger)disabledWhileAway
{
[self.config setDisabledWhileAway:disabledWhileAway forEvent:self.eventType];
}
- (NSUInteger)bounceDockIcon
{
return [self.config bounceDockIconForEvent:self.eventType];
}
- (void)setBounceDockIcon:(NSUInteger)bounceDockIcon
{
[self.config setBounceDockIcon:bounceDockIcon forEvent:self.eventType];
}
- (NSUInteger)bounceDockIconRepeatedly
{
return [self.config bounceDockIconRepeatedlyForEvent:self.eventType];
}
- (void)setBounceDockIconRepeatedly:(NSUInteger)bounceDockIconRepeatedly
{
[self.config setBounceDockIconRepeatedly:bounceDockIconRepeatedly forEvent:self.eventType];
}
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Dialogs/TDCChannelPropertiesSheet.m
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "NSObjectHelperPrivate.h"
#import "NSStringHelper.h"
#import "NSViewHelper.h"
#import "IRCClient.h"
#import "IRCChannel.h"
#import "IRCISupportInfo.h"
#import "TPCPreferencesLocal.h"
#import "TLOLocalization.h"
#import "TVCLogControllerInlineMediaServicePrivate.h"
#import "TVCNotificationConfigurationViewControllerPrivate.h"
#import "TVCValidatedTextField.h"
#import "TDCAlert.h"
#import "TDCChannelPropertiesNotificationConfigurationPrivate.h"
#import "TDCChannelPropertiesSheetInternal.h"
NS_ASSUME_NONNULL_BEGIN
typedef NS_ENUM(NSUInteger, TDCChannelPropertiesSheetSelection)
{
TDCChannelPropertiesSheetSelectionGeneral = 0,
TDCChannelPropertiesSheetSelectionDefaults = 1,
TDCChannelPropertiesSheetSelectionNotifications = 2
};
@interface TDCChannelPropertiesSheet ()
@property (nonatomic, strong, readwrite, nullable) IRCClient *client;
@property (nonatomic, strong, readwrite, nullable) IRCChannel *channel;
@property (nonatomic, copy, readwrite, nullable) NSString *clientId;
@property (nonatomic, copy, readwrite, nullable) NSString *channelId;
@property (nonatomic, assign) BOOL isNewConfiguration;
@property (nonatomic, assign) BOOL secretKeyLengthAlertDisplayed;
@property (nonatomic, copy) NSArray *navigationTree;
@property (nonatomic, weak) IBOutlet NSButton *autoJoinCheck;
@property (nonatomic, weak) IBOutlet NSButton *disableInlineMediaCheck;
@property (nonatomic, weak) IBOutlet NSButton *enableInlineMediaCheck;
@property (nonatomic, weak) IBOutlet NSButton *pushNotificationsCheck;
@property (nonatomic, weak) IBOutlet NSButton *showTreeBadgeCountCheck;
@property (nonatomic, weak) IBOutlet NSButton *ignoreHighlightsCheck;
@property (nonatomic, weak) IBOutlet NSButton *ignoreGeneralEventMessagesCheck;
@property (nonatomic, weak) IBOutlet NSSegmentedControl *contentViewTabView;
@property (nonatomic, weak) IBOutlet TVCValidatedTextField *channelNameTextField;
@property (nonatomic, weak) IBOutlet NSTextField *labelTextField;
@property (nonatomic, weak) IBOutlet NSTextField *defaultModesTextField;
@property (nonatomic, weak) IBOutlet NSTextField *defaultTopicTextField;
@property (nonatomic, weak) IBOutlet NSTextField *secretKeyTextField;
@property (nonatomic, strong) IBOutlet NSView *contentView;
@property (nonatomic, strong) IBOutlet NSView *contentViewDefaultsView;
@property (nonatomic, strong) IBOutlet NSView *contentViewGeneralView;
@property (nonatomic, strong) IBOutlet NSView *contentViewNotifications;
@property (nonatomic, strong) IBOutlet NSView *contentViewNotificationsHost;
@property (nonatomic, strong) IBOutlet TVCNotificationConfigurationViewController *notificationsController;
- (IBAction)onMenuBarItemChanged:(id)sender;
- (IBAction)onInlineMediaCheckChanged:(id)sender;
- (IBAction)onPushNotificationsCheckChanged:(id)sender;
@end
@implementation TDCChannelPropertiesSheet
DESIGNATED_INITIALIZER_EXCEPTION_BODY_BEGIN
- (instancetype)initWithWindow:(nullable NSWindow *)window
{
if ((self = [super initWithWindow:window])) {
self.config = [IRCChannelConfigMutable new];
[self prepareInitialState];
[self loadConfig];
return self;
}
return nil;
}
DESIGNATED_INITIALIZER_EXCEPTION_BODY_END
- (instancetype)initWithClient:(IRCClient *)client
{
return [self initWithConfig:nil onClient:client];
}
- (instancetype)initWithClientId:(NSString *)clientId
{
return [self initWithConfig:nil onClientWithId:clientId];
}
- (instancetype)initWithChannel:(IRCChannel *)channel
{
NSParameterAssert(channel != nil);
if ((self = [super initWithWindow:nil])) {
self.client = channel.associatedClient;
self.clientId = channel.associatedClient.uniqueIdentifier;
self.channel = channel;
self.channelId = channel.uniqueIdentifier;
if (channel) {
self.config = [channel.config mutableCopy];
} else {
self.config = [IRCChannelConfigMutable new];
}
[self prepareInitialState];
[self loadConfig];
return self;
}
return nil;
}
- (instancetype)initWithConfig:(nullable IRCChannelConfig *)config
{
return [self initWithConfig:config onClientWithId:nil];
}
- (instancetype)initWithConfig:(nullable IRCChannelConfig *)config onClient:(nullable IRCClient *)client
{
if ((self = [super initWithWindow:nil])) {
self.client = client;
self.clientId = client.uniqueIdentifier;
if (config) {
self.config = [config mutableCopy];
} else {
self.config = [IRCChannelConfigMutable new];
}
[self prepareInitialState];
[self loadConfig];
return self;
}
return nil;
}
- (instancetype)initWithConfig:(nullable IRCChannelConfig *)config onClientWithId:(nullable NSString *)clientId
{
if ((self = [self initWithWindow:nil])) {
self.clientId = clientId;
if (config) {
self.config = [config mutableCopy];
} else {
self.config = [IRCChannelConfigMutable new];
}
[self prepareInitialState];
[self loadConfig];
return self;
}
return nil;
}
- (void)prepareInitialState
{
[RZMainBundle() loadNibNamed:@"TDCChannelPropertiesSheet" owner:self topLevelObjects:nil];
self.navigationTree = @[
// view first responder
@[self.contentViewGeneralView, self.channelNameTextField],
@[self.contentViewDefaultsView, self.defaultTopicTextField],
@[self.contentViewNotifications, [NSNull null]],
];
self.channelNameTextField.stringValueIsInvalidOnEmpty = YES;
self.channelNameTextField.stringValueUsesOnlyFirstToken = YES;
self.channelNameTextField.textDidChangeCallback = self;
self.channelNameTextField.validationBlock = ^NSString *(NSString *currentValue) {
if (currentValue.isChannelName == NO) {
return TXTLS(@"TDCChannelPropertiesSheet[1nd-7x]");
}
return nil;
};
[self addConfigurationDidChangeObserver];
[self setupNotificationsController];
}
- (void)setupNotificationsController
{
self.notificationsController.allowsMixedState = YES;
NSMutableArray *notifications = [NSMutableArray array];
[notifications addObject:[[TDCChannelPropertiesNotificationConfiguration alloc] initWithEventType:TXNotificationTypeHighlight inSheet:self]];
[notifications addObject:@" "];
[notifications addObject:[[TDCChannelPropertiesNotificationConfiguration alloc] initWithEventType:TXNotificationTypeChannelMessage inSheet:self]];
[notifications addObject:[[TDCChannelPropertiesNotificationConfiguration alloc] initWithEventType:TXNotificationTypeChannelNotice inSheet:self]];
[notifications addObject:@" "];
[notifications addObject:[[TDCChannelPropertiesNotificationConfiguration alloc] initWithEventType:TXNotificationTypeUserJoined inSheet:self]];
[notifications addObject:[[TDCChannelPropertiesNotificationConfiguration alloc] initWithEventType:TXNotificationTypeUserParted inSheet:self]];
self.notificationsController.notifications = notifications;
[self.notificationsController attachToView:self.contentViewNotificationsHost];
}
- (void)reloadNotificationsController
{
[self.notificationsController reload];
}
- (void)updateNavigationEnabledState
{
[self.contentViewTabView setEnabled:(self.pushNotificationsCheck.state == NSControlStateValueOn)
forSegment:TDCChannelPropertiesSheetSelectionNotifications];
}
- (void)loadConfig
{
self.channelNameTextField.stringValue = self.config.channelName;
self.channelNameTextField.editable = (self.config.channelName.length == 0);
self.labelTextField.stringValue = self.config.label;
self.defaultModesTextField.stringValue = self.config.defaultModes;
self.defaultTopicTextField.stringValue = self.config.defaultTopic;
self.secretKeyTextField.stringValue = self.config.secretKey;
self.autoJoinCheck.state = self.config.autoJoin;
self.pushNotificationsCheck.state = self.config.pushNotifications;
self.showTreeBadgeCountCheck.state = self.config.showTreeBadgeCount;
self.ignoreGeneralEventMessagesCheck.state = self.config.ignoreGeneralEventMessages;
self.ignoreHighlightsCheck.state = self.config.ignoreHighlights;
self.disableInlineMediaCheck.state = self.config.inlineMediaDisabled;
self.enableInlineMediaCheck.state = self.config.inlineMediaEnabled;
[self updateNavigationEnabledState];
}
- (void)onMenuBarItemChanged:(id)sender
{
[self _navigateToSelection:[sender indexOfSelectedItem]];
}
- (void)navigateToSelection:(TDCChannelPropertiesSheetSelection)selection
{
if (self.contentViewTabView.indexOfSelectedItem == selection) {
return;
}
[self.contentViewTabView selectSegmentWithTag:selection];
[self _navigateToSelection:selection];
}
- (void)_navigateToSelection:(TDCChannelPropertiesSheetSelection)selection
{
[self selectPane:self.navigationTree[selection][0]];
id firstResponder = self.navigationTree[selection][1];
if ([firstResponder isKindOfClass:[NSControl class]]) {
[self.sheet makeFirstResponder:firstResponder];
}
}
- (void)selectPane:(NSView *)view
{
[self.contentView replaceFirstSubview:view];
}
- (void)start
{
[self startSheet];
[self _navigateToSelection:TDCChannelPropertiesSheetSelectionGeneral];
}
- (void)controlTextDidChange:(NSNotification *)aNotification
{
if (aNotification.object == self.secretKeyTextField) {
[self updateSecretKeyLengthAlert];
}
}
- (void)updateSecretKeyLengthAlert
{
NSUInteger maximumKeyLength = self.client.supportInfo.maximumKeyLength;
if (maximumKeyLength == 0) {
return;
}
NSUInteger currentKeyLength = self.secretKeyTextField.stringValue.length;
if (currentKeyLength <= maximumKeyLength) {
return;
}
if (self.secretKeyLengthAlertDisplayed == NO) {
self.secretKeyLengthAlertDisplayed = YES;
} else {
return;
}
[TDCAlert alertSheetWithWindow:self.sheet
body:TXTLS(@"TDCChannelPropertiesSheet[op4-gg]")
title:TXTLS(@"TDCChannelPropertiesSheet[zf2-r7]", self.client.networkNameAlt, maximumKeyLength)
defaultButton:TXTLS(@"Prompts[c7s-dq]")
alternateButton:nil
otherButton:nil
suppressionKey:@"maximum_secret_key_length"
suppressionText:nil
completionBlock:nil];
}
- (void)addConfigurationDidChangeObserver
{
if (self.channel == nil) {
return;
}
[RZNotificationCenter() addObserver:self
selector:@selector(underlyingConfigurationChanged:)
name:IRCChannelConfigurationWasUpdatedNotification
object:self.channel];
}
- (void)removeConfigurationDidChangeObserver
{
[RZNotificationCenter() removeObserver:self];
}
- (void)underlyingConfigurationChanged:(NSNotification *)notification
{
IRCChannel *channel = notification.object;
NSWindow *window = self.sheet;
[TDCAlert alertSheetWithWindow:window
body:TXTLS(@"TDCChannelPropertiesSheet[qby-hi]")
title:TXTLS(@"TDCChannelPropertiesSheet[mvl-r5]")
defaultButton:TXTLS(@"Prompts[mvh-ms]")
alternateButton:TXTLS(@"Prompts[99q-gg]")
otherButton:nil
completionBlock:^(TDCAlertResponse buttonClicked, BOOL suppressed, id underlyingAlert) {
if (buttonClicked != TDCAlertResponseDefault) {
return;
}
[self close];
self.config = [channel.config copy];
[self loadConfig];
[self reloadNotificationsController];
[self start];
}];
}
- (void)onInlineMediaCheckChanged:(id)sender
{
if (self.enableInlineMediaCheck.state != NSControlStateValueOn) {
return;
}
[TVCLogControllerInlineMediaService askPermissionToEnableInlineMediaWithCompletionBlock:^(BOOL granted) {
if (granted == NO) {
self.enableInlineMediaCheck.state = NSControlStateValueOff;
}
}];
}
- (void)onPushNotificationsCheckChanged:(id)sender
{
[self updateNavigationEnabledState];
}
#pragma mark -
#pragma mark Actions
- (void)cancel:(id)sender
{
[self removeConfigurationDidChangeObserver];
[super cancel:sender];
}
- (void)ok:(id)sender
{
if ([self okOrError] == NO) {
return;
}
[self removeConfigurationDidChangeObserver];
self.config.channelName = self.channelNameTextField.value;
self.config.label = self.labelTextField.trimmedStringValue;
self.config.defaultModes = self.defaultModesTextField.trimmedStringValue;
self.config.defaultTopic = self.defaultTopicTextField.trimmedStringValue;
self.config.secretKey = self.secretKeyTextField.trimmedFirstTokenStringValue;
self.config.autoJoin = self.autoJoinCheck.state;
self.config.pushNotifications = self.pushNotificationsCheck.state;
self.config.showTreeBadgeCount = self.showTreeBadgeCountCheck.state;
self.config.ignoreGeneralEventMessages = self.ignoreGeneralEventMessagesCheck.state;
self.config.ignoreHighlights = self.ignoreHighlightsCheck.state;
self.config.inlineMediaDisabled = self.disableInlineMediaCheck.state;
self.config.inlineMediaEnabled = self.enableInlineMediaCheck.state;
if ([self.delegate respondsToSelector:@selector(channelPropertiesSheet:onOk:)]) {
[self.delegate channelPropertiesSheet:self onOk:[self.config copy]];
}
[super ok:nil];
}
- (BOOL)okOrError
{
return [self okOrErrorForTextField:self.channelNameTextField inSelection:TDCChannelPropertiesSheetSelectionGeneral];
}
- (BOOL)okOrErrorForTextField:(TVCValidatedTextField *)textField inSelection:(TDCChannelPropertiesSheetSelection)selection
{
if (textField.valueIsValid) {
return YES;
}
[self navigateToSelection:selection];
/* Give navigation time to settle before trying to attach popover */
XRPerformBlockAsynchronouslyOnMainQueue(^{
[textField showValidationErrorPopover];
});
return NO;
}
#pragma mark -
#pragma mark NSWindow Delegate
- (void)windowWillClose:(NSNotification *)note
{
[self.sheet makeFirstResponder:nil];
if ([self.delegate respondsToSelector:@selector(channelPropertiesSheetWillClose:)]) {
[self.delegate channelPropertiesSheetWillClose:self];
}
}
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Dialogs/TDCHighlightEntrySheet.m
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2008 - 2010 Satoshi Nakagawa
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "NSObjectHelperPrivate.h"
#import "IRCChannelConfig.h"
#import "IRCHighlightMatchCondition.h"
#import "TVCValidatedTextField.h"
#import "TDCHighlightEntrySheetPrivate.h"
NS_ASSUME_NONNULL_BEGIN
@interface TDCHighlightEntrySheet ()
@property (nonatomic, strong) IRCHighlightMatchConditionMutable *config;
@property (nonatomic, copy) NSArray *channelList;
@property (nonatomic, weak) IBOutlet TVCValidatedTextField *matchKeywordTextField;
@property (nonatomic, weak) IBOutlet NSPopUpButton *matchTypePopupButton;
@property (nonatomic, weak) IBOutlet NSPopUpButton *matchChannelPopupButton;
@end
@implementation TDCHighlightEntrySheet
- (instancetype)initWithConfig:(nullable IRCHighlightMatchCondition *)config
{
if ((self = [super initWithWindow:nil])) {
if (config) {
self.config = [config mutableCopy];
} else {
self.config = [IRCHighlightMatchConditionMutable new];
}
[self prepareInitialState];
[self loadConfig];
return self;
}
return nil;
}
- (void)prepareInitialState
{
[RZMainBundle() loadNibNamed:@"TDCHighlightEntrySheet" owner:self topLevelObjects:nil];
self.matchKeywordTextField.stringValueUsesOnlyFirstToken = NO;
self.matchKeywordTextField.stringValueIsInvalidOnEmpty = YES;
self.matchKeywordTextField.stringValueIsTrimmed = YES;
self.matchKeywordTextField.textDidChangeCallback = self;
}
- (void)loadConfig
{
self.matchKeywordTextField.stringValue = self.config.matchKeyword;
if (self.config.matchIsExcluded == NO) {
[self.matchTypePopupButton selectItemWithTag:1];
} else {
[self.matchTypePopupButton selectItemWithTag:2];
}
}
- (void)startWithChannels:(NSArray *)channels
{
NSParameterAssert(channels != nil);
self.channelList = channels;
NSString *matchChannelId = self.config.matchChannelId;
NSUInteger channelCount = 0;
for (IRCChannelConfig *channel in self.channelList) {
NSString *channelName = channel.channelName;
[self.matchChannelPopupButton addItemWithTitle:channelName];
if ([channel.uniqueIdentifier isEqualToString:matchChannelId]) {
[self.matchChannelPopupButton selectItemWithTitle:channelName];
}
channelCount += 1;
}
if (channelCount == 0) {
[self.matchChannelPopupButton removeItemAtIndex:1];
}
[self startSheet];
[self.sheet makeFirstResponder:self.matchKeywordTextField];
}
- (void)ok:(id)sender
{
if ([self okOrError] == NO) {
return;
}
self.config.matchIsExcluded = (self.matchTypePopupButton.selectedTag == 2);
self.config.matchKeyword = self.matchKeywordTextField.value;
NSInteger selectedChannelIndex = self.matchChannelPopupButton.indexOfSelectedItem;
if (selectedChannelIndex > 0) {
NSString *selectedChannelName = self.matchChannelPopupButton.titleOfSelectedItem;
for (IRCChannelConfig *c in self.channelList) {
if ([c.channelName isEqualToString:selectedChannelName]) {
self.config.matchChannelId = c.uniqueIdentifier;
break;
}
}
}
[self.delegate highlightEntrySheet:self onOk:[self.config copy]];
[super ok:sender];
}
- (BOOL)okOrError
{
return [self okOrErrorForTextField:self.matchKeywordTextField];
}
#pragma mark -
#pragma mark NSWindow Delegate
- (void)windowWillClose:(NSNotification *)note
{
[self.delegate highlightEntrySheetWillClose:self];
}
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Dialogs/TDCInputPrompt.m
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "TDCInputPrompt.h"
NS_ASSUME_NONNULL_BEGIN
@implementation TDCInputPrompt
+ (TVCAlertResponseButton)promptWithMessage:(NSString *)bodyText
title:(NSString *)titleText
defaultButton:(NSString *)buttonDefault
alternateButton:(nullable NSString *)buttonAlternate
prefillString:(nullable NSString *)prefillString
resultString:(NSString * _Nonnull * _Nonnull )resultString
{
NSParameterAssert(bodyText != nil);
NSParameterAssert(titleText != nil);
NSParameterAssert(buttonDefault != nil);
/* Create text field */
NSTextField *textField = [NSTextField new];
textField.translatesAutoresizingMaskIntoConstraints = NO;
[textField addConstraints:
@[
[NSLayoutConstraint constraintWithItem:textField
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:295.0],
[NSLayoutConstraint constraintWithItem:textField
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:22.0]
]
];
textField.editable = YES;
textField.selectable = YES;
textField.drawsBackground = YES;
textField.bordered = YES;
textField.bezeled = YES;
textField.cell.lineBreakMode = NSLineBreakByTruncatingTail;
if (prefillString) {
textField.stringValue = prefillString;
}
/* Create alert */
TVCAlert *alert = [TVCAlert new];
alert.messageText = titleText;
alert.informativeText = bodyText;
[alert setTitle:buttonDefault forButton:TVCAlertResponseButtonFirst];
[alert setTitle:buttonAlternate forButton:TVCAlertResponseButtonSecond];
alert.accessoryView = textField;
alert.window.initialFirstResponder = textField;
/* Run modal */
TVCAlertResponseButton response = [alert runModal];
/* Assign result */
*resultString = textField.stringValue;
/* Return response */
return response;
}
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Dialogs/TDCNicknameColorSheet.m
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "NSObjectHelperPrivate.h"
#import "IRCUserNicknameColorStyleGeneratorPrivate.h"
#import "TDCNicknameColorSheetPrivate.h"
NS_ASSUME_NONNULL_BEGIN
@interface TDCNicknameColorSheet ()
@property (nonatomic, copy) NSString *nickname;
@property (nonatomic, weak) IBOutlet NSColorWell *nicknameColorWell;
- (IBAction)resetNicknameColor:(id)sender;
@end
@implementation TDCNicknameColorSheet
- (instancetype)initWithNickname:(NSString *)nickname
{
NSParameterAssert(nickname != nil);
if ((self = [super initWithWindow:nil])) {
self.nickname = nickname;
[self prepareInitialState];
return self;
}
return nil;
}
- (void)prepareInitialState
{
[RZMainBundle() loadNibNamed:@"TDCNicknameColorSheet" owner:self topLevelObjects:nil];
NSColor *nicknameColor =
[IRCUserNicknameColorStyleGenerator nicknameColorStyleOverrideForKey:self.nickname];
if (nicknameColor == nil) {
nicknameColor = [NSColor whiteColor];
}
self.nicknameColorWell.color = nicknameColor;
}
- (void)start
{
[self startSheet];
}
- (void)ok:(id)sender
{
NSColor *nicknameColor = self.nicknameColorWell.color;
if ([nicknameColor isEqual:[NSColor whiteColor]]) {
nicknameColor = nil;
}
[IRCUserNicknameColorStyleGenerator setNicknameColorStyleOverride:nicknameColor forKey:self.nickname];
if ([self.delegate respondsToSelector:@selector(nicknameColorSheetOnOk:)]) {
[self.delegate nicknameColorSheetOnOk:self];
}
[super ok:nil];
}
- (void)resetNicknameColor:(id)sender
{
if ([NSColorPanel sharedColorPanelExists]) {
[[NSColorPanel sharedColorPanel] close];
}
self.nicknameColorWell.color = [NSColor whiteColor];
}
#pragma mark -
#pragma mark NSWindow Delegate
- (void)windowWillClose:(NSNotification *)note
{
if ([self.delegate respondsToSelector:@selector(nicknameColorSheetWillClose:)]) {
[self.delegate nicknameColorSheetWillClose:self];
}
}
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Dialogs/TDCProgressIndicatorSheet.m
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "NSObjectHelperPrivate.h"
#import "TDCProgressIndicatorSheetPrivate.h"
NS_ASSUME_NONNULL_BEGIN
@interface TDCProgressIndicatorSheet ()
@property (nonatomic, weak) IBOutlet NSProgressIndicator *progressIndicator;
@end
@implementation TDCProgressIndicatorSheet
- (instancetype)initWithWindow:(nullable NSWindow *)window
{
NSParameterAssert(window != nil);
if ((self = [super initWithWindow:window])) {
[self prepareInitialState];
return self;
}
return nil;
}
- (void)prepareInitialState
{
[RZMainBundle() loadNibNamed:@"TDCProgressIndicatorSheet" owner:self topLevelObjects:nil];
}
- (void)start
{
[self.progressIndicator startAnimation:nil];
[self startSheet];
}
- (void)stop
{
[self.progressIndicator stopAnimation:nil];
[self close];
}
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Dialogs/TDCServerChangeNicknameSheet.m
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2008 - 2010 Satoshi Nakagawa
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "NSObjectHelperPrivate.h"
#import "NSStringHelper.h"
#import "IRCClient.h"
#import "TLOLocalization.h"
#import "TVCValidatedTextField.h"
#import "TDCServerChangeNicknameSheetPrivate.h"
NS_ASSUME_NONNULL_BEGIN
@interface TDCServerChangeNicknameSheet ()
@property (nonatomic, strong, readwrite) IRCClient *client;
@property (nonatomic, copy, readwrite) NSString *clientId;
@property (nonatomic, weak) IBOutlet TVCValidatedTextField *tnewNicknameTextField;
@property (nonatomic, weak) IBOutlet NSTextField *toldNicknameTextField;
@end
@implementation TDCServerChangeNicknameSheet
- (instancetype)initWithClient:(IRCClient *)client
{
NSParameterAssert(client != nil);
if ((self = [super initWithWindow:nil])) {
self.client = client;
self.clientId = client.uniqueIdentifier;
[self prepareInitialState];
return self;
}
return nil;
}
- (void)prepareInitialState
{
[RZMainBundle() loadNibNamed:@"TDCServerChangeNicknameSheet" owner:self topLevelObjects:nil];
self.tnewNicknameTextField.stringValueIsInvalidOnEmpty = YES;
self.tnewNicknameTextField.stringValueUsesOnlyFirstToken = YES;
self.tnewNicknameTextField.textDidChangeCallback = self;
self.tnewNicknameTextField.validationBlock = ^NSString *(NSString *currentValue) {
if ([currentValue isHostmaskNicknameOn:self.client] == NO) {
return TXTLS(@"CommonErrors[och-j5]");
}
return nil;
};
NSString *nickname = self.client.userNickname;
self.tnewNicknameTextField.stringValue = nickname;
self.toldNicknameTextField.stringValue = nickname;
}
- (void)start
{
[self startSheet];
[self.sheet makeFirstResponder:self.tnewNicknameTextField];
}
- (void)ok:(id)sender
{
if ([self okOrError] == NO) {
return;
}
if ([self.delegate respondsToSelector:@selector(serverChangeNicknameSheet:didInputNickname:)]) {
NSString *newNickname = self.tnewNicknameTextField.value;
[self.delegate serverChangeNicknameSheet:self didInputNickname:newNickname];
}
[super ok:sender];
}
- (BOOL)okOrError
{
return [self okOrErrorForTextField:self.tnewNicknameTextField];
}
#pragma mark -
#pragma mark NSWindow Delegate
- (void)windowWillClose:(NSNotification *)note
{
if ([self.delegate respondsToSelector:@selector(serverChangeNicknameSheetWillClose:)]) {
[self.delegate serverChangeNicknameSheetWillClose:self];
}
}
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Dialogs/TDCServerChannelListDialog.m
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2008 - 2010 Satoshi Nakagawa
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "NSColorHelper.h"
#import "NSObjectHelperPrivate.h"
#import "NSStringHelper.h"
#import "TXGlobalModels.h"
#import "NSTableViewHelperPrivate.h"
#import "TLOLocalization.h"
#import "IRCClient.h"
#import "TVCBasicTableView.h"
#import "TDCServerChannelListDialogPrivate.h"
NS_ASSUME_NONNULL_BEGIN
@interface TDCServerChannelListDialogEntry : NSObject
@property (nonatomic, copy) NSString *channelName;
@property (nonatomic, copy) NSNumber *channelMemberCount;
@property (nonatomic, copy) NSString *channelTopicUnformatted;
@property (nonatomic, copy) NSAttributedString *channelTopicFormatted;
@end
@interface TDCServerChannelListDialog ()
@property (nonatomic, strong, readwrite) IRCClient *client;
@property (nonatomic, copy, readwrite) NSString *clientId;
@property (nonatomic, assign) BOOL isWaitingForWrites;
@property (nonatomic, strong) NSMutableArray *queuedWrites;
@property (nonatomic, weak) IBOutlet NSButton *updateButton;
@property (nonatomic, weak) IBOutlet NSSearchField *searchTextField;
@property (nonatomic, weak) IBOutlet NSTextField *networkNameTextField;
@property (nonatomic, weak) IBOutlet TVCBasicTableView *channelListTable;
@property (nonatomic, strong) IBOutlet NSArrayController *channelListController;
- (IBAction)onClose:(id)sender;
- (IBAction)onUpdate:(id)sender;
- (IBAction)onJoinChannels:(id)sender;
@end
@implementation TDCServerChannelListDialog
- (instancetype)init
{
[self doesNotRecognizeSelector:_cmd];
return nil;
}
- (instancetype)initWithClient:(IRCClient *)client
{
NSParameterAssert(client != nil);
if ((self = [super init])) {
self.client = client;
self.clientId = client.uniqueIdentifier;
[self prepareInitialState];
return self;
}
return nil;
}
- (void)prepareInitialState
{
[RZMainBundle() loadNibNamed:@"TDCServerChannelListDialog" owner:self topLevelObjects:nil];
self.queuedWrites = [NSMutableArray array];
self.channelListTable.doubleAction = @selector(onJoin:);
self.channelListTable.sortDescriptors = @[
[NSSortDescriptor sortDescriptorWithKey:@"channelMemberCount" ascending:NO selector:@selector(compare:)]
];
self.networkNameTextField.stringValue = TXTLS(@"TDCServerChannelListDialog[7qf-r0]", self.client.networkNameAlt);
}
- (void)show
{
[self.window restoreWindowStateForClass:self.class];
[super show];
}
- (void)clear
{
self.channelListController.content = nil;
[self updateDialogTitle];
}
- (void)addChannel:(NSString *)channel count:(NSUInteger)count topic:(nullable NSString *)topic
{
NSParameterAssert(channel != nil);
TDCServerChannelListDialogEntry *newEntry = [TDCServerChannelListDialogEntry new];
newEntry.channelName = channel;
newEntry.channelMemberCount = @(count);
if (topic == nil) {
newEntry.channelTopicUnformatted = @"";
newEntry.channelTopicFormatted = [NSAttributedString attributedString];
} else {
newEntry.channelTopicUnformatted = topic;
NSAttributedString *topicFormatted =
[topic attributedStringWithIRCFormatting:[NSTableView preferredGlobalTableViewFont]
preferredFontColor:[NSColor controlTextColor]];
newEntry.channelTopicFormatted = topicFormatted;
}
@synchronized(self.queuedWrites) {
[self.queuedWrites addObject:newEntry];
}
if (self.isWaitingForWrites == NO) {
self.isWaitingForWrites = YES;
[self performSelectorInCommonModes:@selector(queuedWritesTimer) withObject:nil afterDelay:1.0];
}
}
- (void)queuedWritesTimer
{
self.isWaitingForWrites = NO;
[self writeQueuedWrites];
}
- (void)writeQueuedWrites
{
@synchronized(self.queuedWrites) {
if (self.queuedWrites.count == 0) {
return;
}
NSPredicate *filterPredicate = self.channelListController.filterPredicate;
if (filterPredicate) {
NSMutableArray *queuedWrites = [NSMutableArray array];
for (TDCServerChannelListDialogEntry *queuedWrite in self.queuedWrites) {
if ([filterPredicate evaluateWithObject:queuedWrite]) {
[queuedWrites addObject:queuedWrite];
}
}
[self.channelListController addObjects:queuedWrites];
[self.queuedWrites removeObjectsInArray:queuedWrites];
} else {
[self.channelListController addObjects:self.queuedWrites];
[self.queuedWrites removeAllObjects];
}
}
[self updateDialogTitle];
}
- (void)controlTextDidChange:(NSNotification *)obj
{
if (obj.object == self.searchTextField) {
NSString *currentSearchValue = self.searchTextField.stringValue;
if (currentSearchValue.length == 0) {
[self writeQueuedWrites];
}
}
}
- (void)updateDialogTitle
{
id arrangedObjects = self.channelListController.arrangedObjects;
NSString *arrangedObjectsCount = TXFormattedNumber([arrangedObjects count]);
self.window.title = TXTLS(@"TDCServerChannelListDialog[ct4-wh]", arrangedObjectsCount);
}
#pragma mark -
#pragma mark Actions
- (void)onClose:(id)sender
{
[self close];
}
- (void)onUpdate:(id)sender
{
[self clear];
if ([self.delegate respondsToSelector:@selector(serverChannelListDialogOnUpdate:)]) {
[self.delegate serverChannelListDialogOnUpdate:self];
}
}
/* onJoinChannels: handles join for selected items. */
- (void)onJoinChannels:(id)sender
{
[self onJoin:sender];
}
/* onJoin: is a legacy method. It handles join on double click. */
- (void)onJoin:(id)sender
{
NSIndexSet *selectedRows = self.channelListTable.selectedRowIndexes;
NSMutableArray *channelNames = [NSMutableArray arrayWithCapacity:selectedRows.count];
[selectedRows enumerateIndexesUsingBlock:^(NSUInteger index, BOOL *stop) {
TDCServerChannelListDialogEntry *channelEntry = self.channelListController.arrangedObjects[index];
[channelNames addObject:channelEntry.channelName];
}];
if ([self.delegate respondsToSelector:@selector(serverChannelListDialog:joinChannels:)]) {
[self.delegate serverChannelListDialog:self joinChannels:[channelNames copy]];
}
[self.channelListTable deselectAll:nil];
}
#pragma mark -
#pragma mark NSTableViewDelegate
- (NSIndexSet *)tableView:(NSTableView *)tableView selectionIndexesForProposedSelection:(NSIndexSet *)proposedSelectionIndexes
{
#define _maximumSelectedRows 8
return [tableView selectionIndexesForProposedSelection:proposedSelectionIndexes maximumNumberOfSelections:_maximumSelectedRows];
#undef _maximumSelectedRows
}
#pragma mark -
#pragma mark NSWindow Delegate
- (void)windowWillClose:(NSNotification *)note
{
[self cancelPerformRequests];
self.channelListTable.dataSource = nil;
self.channelListTable.delegate = nil;
[self.window saveWindowStateForClass:self.class];
if ([self.delegate respondsToSelector:@selector(serverChannelDialogWillClose:)]) {
[self.delegate serverChannelDialogWillClose:self];
}
}
@end
#pragma mark -
@implementation TDCServerChannelListDialogEntry
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Dialogs/TDCServerHighlightListSheet.m
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "TXMasterController.h"
#import "IRCClient.h"
#import "IRCChannel.h"
#import "IRCHighlightLogEntryPrivate.h"
#import "TVCBasicTableView.h"
#import "TVCMainWindow.h"
#import "TDCServerHighlightListSheetPrivate.h"
NS_ASSUME_NONNULL_BEGIN
#define _renderedMessageTextFieldLeftRightPadding 2.0
@interface TDCServerHighlightListSheet ()
@property (nonatomic, strong, readwrite) IRCClient *client;
@property (nonatomic, copy, readwrite) NSString *clientId;
@property (nonatomic, weak) IBOutlet NSTextField *headerTitleTextField;
@property (nonatomic, weak) IBOutlet TVCBasicTableView *highlightListTable;
@property (nonatomic, strong) IBOutlet NSArrayController *highlightListController;
- (IBAction)onClearList:(id)sender;
@end
@implementation TDCServerHighlightListSheet
- (instancetype)initWithClient:(IRCClient *)client
{
NSParameterAssert(client != nil);
if ((self = [super initWithWindow:nil])) {
self.client = client;
self.clientId = client.uniqueIdentifier;
[self prepareInitialState];
return self;
}
return nil;
}
- (void)prepareInitialState
{
[RZMainBundle() loadNibNamed:@"TDCServerHighlightListSheet" owner:self topLevelObjects:nil];
self.highlightListTable.doubleAction = @selector(highlightDoubleClicked:);
self.highlightListTable.pasteboardDelegate = self;
self.highlightListTable.sortDescriptors = @[
[NSSortDescriptor sortDescriptorWithKey:@"timeLogged" ascending:NO selector:@selector(compare:)],
[NSSortDescriptor sortDescriptorWithKey:@"channelName" ascending:NO selector:@selector(caseInsensitiveCompare:)]
];
NSString *headerTitle = [NSString stringWithFormat:self.headerTitleTextField.stringValue, self.client.networkNameAlt];
self.headerTitleTextField.stringValue = headerTitle;
NSArray *cachedHighlights = self.client.cachedHighlights;
if (cachedHighlights) {
[self addEntry:cachedHighlights];
}
}
- (void)start
{
[self startSheet];
}
- (void)addEntry:(id)newEntry
{
NSParameterAssert(newEntry != nil);
if ([newEntry isKindOfClass:[NSArray class]])
{
for (id entry in newEntry) {
[self addEntry:entry];
}
}
else if ([newEntry isKindOfClass:[IRCHighlightLogEntry class]])
{
if ([newEntry isKindOfClass:[IRCHighlightLogEntryMutable class]]) {
newEntry = [newEntry copy];
}
[self.highlightListController addObject:newEntry];
}
}
- (void)onClearList:(id)sender
{
self.highlightListController.content = nil;
[self.client clearCachedHighlights];
}
- (void)highlightDoubleClicked:(id)sender
{
NSInteger row = self.highlightListTable.clickedRow;
if (row < 0) {
return;
}
IRCHighlightLogEntry *entryItem = self.highlightListController.arrangedObjects[row];
IRCChannel *channel = entryItem.channel;
if (channel == nil) {
return;
}
TVCLogController *viewController = channel.viewController;
[viewController jumpToLine:entryItem.lineNumber completionHandler:^(BOOL result) {
if (result) {
[mainWindow() select:channel];
[self cancel:nil];
}
}];
}
- (void)copy:(id)sender
{
NSIndexSet *selectedRows = self.highlightListTable.selectedRowIndexes;
if (selectedRows.count == 0) {
return;
}
NSMutableString *stringToCopy = [NSMutableString string];
[selectedRows enumerateIndexesUsingBlock:^(NSUInteger index, BOOL *stop) {
IRCHighlightLogEntry *entryItem = self.highlightListController.arrangedObjects[index];
[stringToCopy appendString:entryItem.description];
if (index != selectedRows.lastIndex) {
[stringToCopy appendString:@"\n"];
}
}];
[RZPasteboard() setStringContent:stringToCopy];
}
#pragma mark -
#pragma mark NSTableView Delegate
- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
{
NSTableCellView *result = [tableView makeViewWithIdentifier:tableColumn.identifier owner:self];
return result;
}
#pragma mark -
#pragma mark NSWindow Delegate
- (void)windowWillClose:(NSNotification *)note
{
self.highlightListTable.dataSource = nil;
self.highlightListTable.delegate = nil;
if ([self.delegate respondsToSelector:@selector(serverHighlightListSheetWillClose:)]) {
[self.delegate serverHighlightListSheetWillClose:self];
}
}
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Dialogs/TDCServerPropertiesSheet.m
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2008 - 2010 Satoshi Nakagawa
* Copyright (c) 2010 - 2019 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import
#import "NSStringHelper.h"
#import "IRCClientConfigPrivate.h"
#import "IRCClient.h"
#import "IRCChannel.h"
#import "IRCHighlightMatchCondition.h"
#import "IRCNetworkList.h"
#import "IRCServer.h"
#import "TLOLocalization.h"
#import "TLOpenLink.h"
#import "TPCPreferencesLocal.h"
#import "TPCPreferencesUserDefaults.h"
#import "TVCBasicTableView.h"
#import "TVCValidatedComboBox.h"
#import "TVCContentNavigationOutlineViewPrivate.h"
#import "TVCValidatedTextField.h"
#import "TDCAddressBookSheetPrivate.h"
#import "TDCAlert.h"
#import "TDCChannelPropertiesSheetPrivate.h"
#import "TDCHighlightEntrySheetPrivate.h"
#import "TDCPreferencesControllerPrivate.h"
#import "TDCServerEndpointListSheetPrivate.h"
#import "TDCServerPropertiesSheetPrivate.h"
NS_ASSUME_NONNULL_BEGIN
#define _tableDragToken @"TDCServerPropertiesSheetTableDragToken"
@interface TDCServerPropertiesSheet ()
@property (nonatomic, strong, readwrite, nullable) IRCClient *client;
@property (nonatomic, copy, readwrite, nullable) NSString *clientId;
@property (nonatomic, strong) IRCClientConfigMutable *config;
@property (nonatomic, copy) NSArray *navigationTreeMatrix;
@property (nonatomic, copy) NSDictionary *encodingList;
@property (nonatomic, strong) IRCNetworkList *networkList;
@property (nonatomic, strong) IBOutlet NSMenu *addAddressBookEntryMenu;
@property (nonatomic, strong) IBOutlet NSView *contentViewAddressBook;
@property (nonatomic, strong) IBOutlet NSView *contentViewAutojoin;
@property (nonatomic, strong) IBOutlet NSView *contentViewClientCertificate;
@property (nonatomic, strong) IBOutlet NSView *contentViewConnectCommands;
@property (nonatomic, strong) IBOutlet NSView *contentViewDisconnectMessages;
@property (nonatomic, strong) IBOutlet NSView *contentViewEncoding;
@property (nonatomic, strong) IBOutlet NSView *contentViewFloodControl;
@property (nonatomic, strong) IBOutlet NSView *contentViewGeneral;
@property (nonatomic, strong) IBOutlet NSView *contentViewHighlights;
@property (nonatomic, strong) IBOutlet NSView *contentViewIdentity;
@property (nonatomic, strong) IBOutlet NSView *contentViewNetworkSocket;
@property (nonatomic, strong) IBOutlet NSView *contentViewProxyServer;
@property (nonatomic, strong) IBOutlet NSView *contentViewProxyServerInputView;
@property (nonatomic, strong) IBOutlet NSView *contentViewProxyServerSystemSocksView;
@property (nonatomic, strong) IBOutlet NSView *contentViewProxyServerTorBrowserView;
@property (nonatomic, strong) IBOutlet NSView *contentViewRedundancy;
@property (nonatomic, strong) IBOutlet NSView *contentViewZncBouncer;
@property (nonatomic, strong, nullable) TDCAddressBookSheet *addressBookSheet;
@property (nonatomic, strong, nullable) TDCHighlightEntrySheet *highlightSheet;
@property (nonatomic, strong, nullable) TDCChannelPropertiesSheet *channelSheet;
@property (nonatomic, strong, nullable) TDCServerEndpointListSheet *serverEndpointSheet;
@property (nonatomic, weak) IBOutlet NSButton *addAddressBookEntryButton;
@property (nonatomic, weak) IBOutlet NSButton *addChannelButton;
@property (nonatomic, weak) IBOutlet NSButton *addHighlightButton;
@property (nonatomic, weak) IBOutlet NSButton *autoConnectCheck;
@property (nonatomic, weak) IBOutlet NSButton *autoDisconnectOnSleepCheck;
@property (nonatomic, weak) IBOutlet NSButton *autoReconnectCheck;
@property (nonatomic, weak) IBOutlet NSButton *autojoinWaitsForNickServCheck;
@property (nonatomic, weak) IBOutlet NSButton *clientCertificateChangeCertificateButton;
@property (nonatomic, weak) IBOutlet NSButton *clientCertificateResetCertificateButton;
@property (nonatomic, weak) IBOutlet NSButton *clientCertificateMD5FingerprintCopyButton;
@property (nonatomic, weak) IBOutlet NSButton *clientCertificateSHA1FingerprintCopyButton;
@property (nonatomic, weak) IBOutlet NSButton *clientCertificateSHA2FingerprintCopyButton;
@property (nonatomic, weak) IBOutlet NSButton *clientCertificateSHA512FingerprintCopyButton;
@property (nonatomic, weak) IBOutlet NSButton *connectionIPv4AddressTypeCheck;
@property (nonatomic, weak) IBOutlet NSButton *connectionIPv6AddressTypeCheck;
@property (nonatomic, weak) IBOutlet NSButton *connectionDefaultAddressTypeCheck;
@property (nonatomic, weak) IBOutlet NSButton *deleteAddressBookEntryButton;
@property (nonatomic, weak) IBOutlet NSButton *deleteChannelButton;
@property (nonatomic, weak) IBOutlet NSButton *deleteHighlightButton;
@property (nonatomic, weak) IBOutlet NSButton *disconnectOnReachabilityChangeCheck;
@property (nonatomic, weak) IBOutlet NSButton *editAddressBookEntryButton;
@property (nonatomic, weak) IBOutlet NSButton *editChannelButton;
@property (nonatomic, weak) IBOutlet NSButton *editHighlightButton;
@property (nonatomic, weak) IBOutlet NSButton *hideAutojoinDelayedWarningsCheck;
@property (nonatomic, weak) IBOutlet NSButton *performDisconnectOnPongTimerCheck;
@property (nonatomic, weak) IBOutlet NSButton *pongTimerCheck;
@property (nonatomic, weak) IBOutlet NSButton *prefersSecuredConnectionCheck;
@property (nonatomic, weak) IBOutlet NSButton *setInvisibleModeOnConnectCheck;
@property (nonatomic, weak) IBOutlet NSButton *validateServerCertificateChainCheck;
@property (nonatomic, weak) IBOutlet NSButton *viewListOfPreferredCipherSuitesButton;
@property (nonatomic, weak) IBOutlet NSButton *zncIgnoreConfiguredAutojoinCheck;
@property (nonatomic, weak) IBOutlet NSButton *zncIgnorePlaybackNotificationsCheck;
@property (nonatomic, weak) IBOutlet NSButton *zncOnlyPlaybackLatestCheck;
@property (nonatomic, weak) IBOutlet NSPopUpButton *fallbackEncodingButton;
@property (nonatomic, weak) IBOutlet NSPopUpButton *primaryEncodingButton;
@property (nonatomic, weak) IBOutlet NSPopUpButton *preferredCipherSuitesButton;
@property (nonatomic, weak) IBOutlet NSPopUpButton *proxyTypeButton;
@property (nonatomic, weak) IBOutlet NSSlider *floodControlDelayTimerSlider;
@property (nonatomic, weak) IBOutlet NSSlider *floodControlMessageCountSlider;
@property (nonatomic, weak) IBOutlet NSTextField *clientCertificateCommonNameField;
@property (nonatomic, weak) IBOutlet NSTextField *clientCertificateMD5FingerprintField;
@property (nonatomic, weak) IBOutlet NSTextField *clientCertificateSHA1FingerprintField;
@property (nonatomic, weak) IBOutlet NSTextField *clientCertificateSHA2FingerprintField;
@property (nonatomic, weak) IBOutlet NSTextField *clientCertificateSHA512FingerprintField;
@property (nonatomic, weak) IBOutlet NSTextField *nicknamePasswordTextField;
@property (nonatomic, weak) IBOutlet NSTextField *proxyPasswordTextField;
@property (nonatomic, weak) IBOutlet NSTextField *proxyUsernameTextField;
@property (nonatomic, weak) IBOutlet NSTextField *serverPasswordTextField;
@property (nonatomic, weak) IBOutlet TVCBasicTableView *addressBookTable;
@property (nonatomic, weak) IBOutlet TVCBasicTableView *channelListTable;
@property (nonatomic, weak) IBOutlet TVCBasicTableView *highlightsTable;
@property (nonatomic, weak) IBOutlet TVCValidatedComboBox *serverAddressComboBox;
@property (nonatomic, weak) IBOutlet TVCContentNavigationOutlineView *navigationOutlineView;
@property (nonatomic, weak) IBOutlet TVCValidatedTextField *alternateNicknamesTextField;
@property (nonatomic, weak) IBOutlet TVCValidatedTextField *awayNicknameTextField;
@property (nonatomic, weak) IBOutlet TVCValidatedTextField *connectionNameTextField;
@property (nonatomic, weak) IBOutlet TVCValidatedTextField *nicknameTextField;
@property (nonatomic, weak) IBOutlet TVCValidatedTextField *normalLeavingCommentTextField;
@property (nonatomic, weak) IBOutlet TVCValidatedTextField *proxyAddressTextField;
@property (nonatomic, weak) IBOutlet TVCValidatedTextField *proxyPortTextField;
@property (nonatomic, weak) IBOutlet TVCValidatedTextField *realNameTextField;
@property (nonatomic, weak) IBOutlet TVCValidatedTextField *serverPortTextField;
@property (nonatomic, weak) IBOutlet TVCValidatedTextField *sleepModeQuitMessageTextField;
@property (nonatomic, weak) IBOutlet TVCValidatedTextField *usernameTextField;
@property (nonatomic, unsafe_unretained) IBOutlet NSTextView *connectCommandsField;
@property (nonatomic, assign) NSUInteger floodControlDelayTimerSliderTempValue;
@property (nonatomic, assign) NSUInteger floodControlMessageCountSliderTempValue;
@property (nonatomic, weak) NSPanel *clientCertificateSelectCertificatePanel;
@property (nonatomic, strong) IBOutlet NSArrayController *addressBookArrayController;
@property (nonatomic, strong) IBOutlet NSArrayController *channelListArrayController;
@property (nonatomic, strong) IBOutlet NSArrayController *highlightListArrayController;
@property (nonatomic, strong) IBOutlet NSArrayController *serverListArrayController;
@property (readonly, copy) NSArray *addressBookList;
@property (readonly, copy) NSArray *channelList;
@property (readonly, copy) NSArray *highlightList;
@property (readonly, copy) NSArray *serverList;
@property (nonatomic, assign) BOOL populatingPrimaryServer;
@property (nonatomic, assign) BOOL primaryServerIsPredefined;
@property (nonatomic, copy, nullable) NSString *lastServerAddressValue;
@property (nonatomic, copy, nullable) IRCServer *previousPrimaryServer;
- (IBAction)proxyTypeChanged:(id)sender;
- (IBAction)toggleAdvancedEncodings:(id)sender;
- (IBAction)addChannel:(id)sender;
- (IBAction)editChannel:(id)sender;
- (IBAction)deleteChannel:(id)sender;
- (IBAction)addHighlight:(id)sender;
- (IBAction)editHighlight:(id)sender;
- (IBAction)deleteHighlight:(id)sender;
- (IBAction)addAddressBookEntry:(id)sender;
- (IBAction)editAddressBookEntry:(id)sender;
- (IBAction)deleteAddressBookEntry:(id)sender;
- (IBAction)showAddAddressBookEntryMenu:(id)sender;
- (IBAction)openProxySettingsInSystemPreferences:(id)sender;
- (IBAction)editSeverEndpoints:(id)sender;
- (IBAction)useSSLCheckChanged:(id)sender;
- (IBAction)autojoinWaitsForNickServChanged:(id)sender;
- (IBAction)onClientCertificateResetRequested:(id)sender;
- (IBAction)onClientCertificateChangeRequested:(id)sender;
- (IBAction)onClientCertificateFingerprintSHA512CopyRequested:(id)sender;
- (IBAction)onClientCertificateFingerprintSHA2CopyRequested:(id)sender;
- (IBAction)onClientCertificateFingerprintSHA1CopyRequested:(id)sender;
- (IBAction)onClientCertificateFingerprintMD5CopyRequested:(id)sender;
- (IBAction)preferredCipherSuitesChanged:(id)sender;
- (IBAction)preferredCipherSuitesViewList:(id)sender;
- (IBAction)preferredInternetProtocolChanged:(id)sender;
@end
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wincomplete-implementation"
@implementation TDCServerPropertiesSheet
- (instancetype)initWithClient:(nullable IRCClient *)client
{
if ((self = [super initWithWindow:nil])) {
if (client) {
self.client = client;
self.clientId = client.uniqueIdentifier;
[client updateStoredConfiguration];
self.config = [client.config mutableCopy];
} else {
self.config = [IRCClientConfigMutable new];
}
[self prepareInitialState];
[self loadConfig];
return self;
}
return nil;
}
- (void)prepareInitialState
{
[RZMainBundle() loadNibNamed:@"TDCServerPropertiesSheet" owner:self topLevelObjects:nil];
/* Populate server list combo box */
self.networkList = [IRCNetworkList new];
NSArray *listOfNetworks = self.networkList.listOfNetworks;
for (IRCNetwork *network in listOfNetworks) {
[self.serverAddressComboBox addItemWithObjectValue:network.networkName];
}
/* Connect commands text box better font */
self.connectCommandsField.font = [NSFont systemFontOfSize:13.0];
self.connectCommandsField.textContainerInset = NSMakeSize(1, 3);
/* Alternate nicknameS */
self.alternateNicknamesTextField.textDidChangeCallback = self;
self.alternateNicknamesTextField.stringValueIsInvalidOnEmpty = NO;
self.alternateNicknamesTextField.stringValueIsTrimmed = YES;
self.alternateNicknamesTextField.validationBlock = ^NSString *(NSString *currentValue) {
NSArray *nicknames = [currentValue componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
for (NSString *nickname in nicknames) {
if (nickname.isHostmaskNickname == NO) {
return TXTLS(@"TDCServerPropertiesSheet[wlz-tb]", nickname);
}
}
return nil;
};
/* Away nickname */
self.awayNicknameTextField.textDidChangeCallback = self;
self.awayNicknameTextField.stringValueIsInvalidOnEmpty = NO;
self.awayNicknameTextField.stringValueIsTrimmed = YES;
self.awayNicknameTextField.stringValueUsesOnlyFirstToken = YES;
self.awayNicknameTextField.validationBlock = ^NSString *(NSString *currentValue) {
if (currentValue.isHostmaskNickname == NO) {
return TXTLS(@"CommonErrors[och-j5]");
}
return nil;
};
/* Nickname */
self.nicknameTextField.textDidChangeCallback = self;
self.nicknameTextField.stringValueIsInvalidOnEmpty = YES;
self.nicknameTextField.stringValueIsTrimmed = YES;
self.nicknameTextField.stringValueUsesOnlyFirstToken = YES;
self.nicknameTextField.validationBlock = ^NSString *(NSString *currentValue) {
if (currentValue.isHostmaskNickname == NO) {
return TXTLS(@"CommonErrors[och-j5]");
}
return nil;
};
/* Username */
self.usernameTextField.textDidChangeCallback = self;
self.usernameTextField.stringValueIsInvalidOnEmpty = YES;
self.usernameTextField.stringValueIsTrimmed = YES;
self.usernameTextField.stringValueUsesOnlyFirstToken = YES;
self.usernameTextField.validationBlock = ^NSString *(NSString *currentValue) {
if (currentValue.isHostmaskUsername == NO) {
return TXTLS(@"TDCServerPropertiesSheet[8iw-q8]");
}
return nil;
};
/* Real name */
self.realNameTextField.textDidChangeCallback = self;
self.realNameTextField.stringValueIsInvalidOnEmpty = YES;
self.realNameTextField.stringValueIsTrimmed = YES;
self.realNameTextField.stringValueUsesOnlyFirstToken = NO;
self.realNameTextField.validationBlock = ^NSString *(NSString *currentValue) {
if ([currentValue containsCharactersFromCharacterSet:[NSCharacterSet newlineCharacterSet]]) {
return TXTLS(@"TDCServerPropertiesSheet[agy-bp]");
}
return nil;
};
/* Normal leaving comment */
self.normalLeavingCommentTextField.textDidChangeCallback = self;
self.normalLeavingCommentTextField.stringValueIsInvalidOnEmpty = NO;
self.normalLeavingCommentTextField.stringValueIsTrimmed = YES;
self.normalLeavingCommentTextField.stringValueUsesOnlyFirstToken = NO;
self.normalLeavingCommentTextField.validationBlock = ^NSString *(NSString *currentValue) {
if ([currentValue containsCharactersFromCharacterSet:[NSCharacterSet newlineCharacterSet]]) {
return TXTLS(@"CommonErrors[gas-v8]");
}
if (currentValue.length > 390) {
return TXTLS(@"CommonErrors[2cb-af]", 390);
}
return nil;
};
/* Sleep mode leaving comment */
self.sleepModeQuitMessageTextField.textDidChangeCallback = self;
self.sleepModeQuitMessageTextField.stringValueIsInvalidOnEmpty = NO;
self.sleepModeQuitMessageTextField.stringValueIsTrimmed = YES;
self.sleepModeQuitMessageTextField.stringValueUsesOnlyFirstToken = NO;
self.sleepModeQuitMessageTextField.validationBlock = ^NSString *(NSString *currentValue) {
if ([currentValue containsCharactersFromCharacterSet:[NSCharacterSet newlineCharacterSet]]) {
return TXTLS(@"CommonErrors[gas-v8]");
}
if (currentValue.length > 390) {
return TXTLS(@"CommonErrors[2cb-af]", 390);
}
return nil;
};
/* Connection name */
self.connectionNameTextField.textDidChangeCallback = self;
self.connectionNameTextField.stringValueIsInvalidOnEmpty = YES;
self.connectionNameTextField.stringValueIsTrimmed = YES;
self.connectionNameTextField.stringValueUsesOnlyFirstToken = NO;
self.connectionNameTextField.validationBlock = ^NSString *(NSString *currentValue) {
if ([currentValue containsCharactersFromCharacterSet:[NSCharacterSet newlineCharacterSet]]) {
return TXTLS(@"CommonErrors[gas-v8]");
}
return nil;
};
/* Server address */
self.serverAddressComboBox.textDidChangeCallback = self;
self.serverAddressComboBox.stringValueIsInvalidOnEmpty = YES;
self.serverAddressComboBox.stringValueIsTrimmed = YES;
self.serverAddressComboBox.stringValueUsesOnlyFirstToken = YES;
self.serverAddressComboBox.validationBlock = ^NSString *(NSString *currentValue) {
if (currentValue.isValidInternetAddress == NO) {
return TXTLS(@"CommonErrors[yyx-l3]");
}
return nil;
};
/* Server port */
self.serverPortTextField.textDidChangeCallback = self;
self.serverPortTextField.stringValueIsInvalidOnEmpty = YES;
self.serverPortTextField.stringValueIsTrimmed = YES;
self.serverPortTextField.stringValueUsesOnlyFirstToken = NO;
self.serverPortTextField.validationBlock = ^NSString *(NSString *currentValue) {
if (currentValue.isValidInternetPort == NO) {
return TXTLS(@"CommonErrors[l0c-nb]");
}
return nil;
};
/* Proxy address */
self.proxyAddressTextField.textDidChangeCallback = self;
self.proxyAddressTextField.stringValueIsInvalidOnEmpty = NO;
self.proxyAddressTextField.stringValueIsTrimmed = YES;
self.proxyAddressTextField.stringValueUsesOnlyFirstToken = YES;
self.proxyAddressTextField.performValidationWhenEmpty = YES;
self.proxyAddressTextField.validationBlock = ^NSString *(NSString *currentValue) {
NSInteger proxyType = self.proxyTypeButton.selectedTag;
if (proxyType == IRCConnectionProxyTypeSocks4 ||
proxyType == IRCConnectionProxyTypeSocks5 ||
proxyType == IRCConnectionProxyTypeHTTP ||
proxyType == IRCConnectionProxyTypeHTTPS)
{
if (currentValue.isValidInternetAddress == NO) {
return TXTLS(@"TDCServerPropertiesSheet[tlo-b6]");
}
}
return nil;
};
/* Proxy port */
self.proxyPortTextField.textDidChangeCallback = self;
self.proxyPortTextField.stringValueIsInvalidOnEmpty = NO;
self.proxyPortTextField.stringValueIsTrimmed = YES;
self.proxyPortTextField.stringValueUsesOnlyFirstToken = NO;
self.proxyPortTextField.performValidationWhenEmpty = YES;
self.proxyPortTextField.defaultValue = [NSString stringWithUnsignedInteger:IRCConnectionDefaultProxyPort];
self.proxyPortTextField.validationBlock = ^NSString *(NSString *currentValue) {
NSInteger proxyType = self.proxyTypeButton.selectedTag;
if (proxyType == IRCConnectionProxyTypeSocks4 ||
proxyType == IRCConnectionProxyTypeSocks5 ||
proxyType == IRCConnectionProxyTypeHTTP ||
proxyType == IRCConnectionProxyTypeHTTPS)
{
if (currentValue.isValidInternetPort == NO) {
return TXTLS(@"CommonErrors[l0c-nb]");
}
}
return nil;
};
/* Setup others */
[self addConfigurationDidChangeObserver];
self.addressBookTable.doubleAction = @selector(tableViewDoubleClicked:);
self.addressBookTable.target = self;
[self.addressBookTable registerForDraggedTypes:@[_tableDragToken]];
self.channelListTable.doubleAction = @selector(tableViewDoubleClicked:);
self.channelListTable.target = self;
[self.channelListTable registerForDraggedTypes:@[_tableDragToken]];
self.highlightsTable.doubleAction = @selector(tableViewDoubleClicked:);
self.highlightsTable.target = self;
[self.highlightsTable registerForDraggedTypes:@[_tableDragToken]];
[self populateEncodings];
[self populateTabViewList];
}
- (void)dealloc
{
self.connectCommandsField = nil;
}
- (void)populateTabViewList
{
#define _groupItem(_label_, _children_) \
[[TVCContentNavigationOutlineViewItem alloc] initWithLabel:TXTLS(_label_) identifier:0 view:nil firstResponder:nil children:(_children_)]
#define _childItem(_label_, _identifier_) \
[[TVCContentNavigationOutlineViewItem alloc] initWithLabel:TXTLS(_label_) identifier:TDCServerPropertiesSheetSelection ##_identifier_ view:self.contentView ##_identifier_ firstResponder:nil]
NSArray *generalSectionChildren = @[
_childItem(@"TDCServerPropertiesSheet[8zc-6y]", AddressBook),
_childItem(@"TDCServerPropertiesSheet[5oz-07]", Autojoin),
_childItem(@"TDCServerPropertiesSheet[hip-13]", ConnectCommands),
_childItem(@"TDCServerPropertiesSheet[8ug-ka]", Encoding),
_childItem(@"TDCServerPropertiesSheet[ehx-4d]", General),
_childItem(@"TDCServerPropertiesSheet[8ik-qo]", Identity),
_childItem(@"TDCServerPropertiesSheet[jtx-hn]", Highlights),
_childItem(@"TDCServerPropertiesSheet[j34-yr]", DisconnectMessages),
];
NSArray *vendorSectionChildren = @[
_childItem(@"TDCServerPropertiesSheet[fsj-7f]", ZncBouncer)
];
NSArray *advancedSectionChildren = @[
_childItem(@"TDCServerPropertiesSheet[ce7-kc]", ClientCertificate),
_childItem(@"TDCServerPropertiesSheet[fcr-w8]", FloodControl),
_childItem(@"TDCServerPropertiesSheet[ffy-xt]", NetworkSocket),
_childItem(@"TDCServerPropertiesSheet[t52-7a]", ProxyServer),
_childItem(@"TDCServerPropertiesSheet[36n-u9]", Redundancy)
];
NSArray *navigationTreeMatrix = @[
_groupItem(@"TDCServerPropertiesSheet[lww-pc]", generalSectionChildren),
_groupItem(@"TDCServerPropertiesSheet[v27-8w]", vendorSectionChildren),
_groupItem(@"TDCServerPropertiesSheet[8uw-tz]", advancedSectionChildren)
];
#undef _groupItem
#undef _childItem
self.navigationOutlineView.navigationTreeMatrix = navigationTreeMatrix;
/* Auto layout will grow view beyond these values.
We are just declaring the default which doesn't matter much. */
self.navigationOutlineView.contentViewPreferredWidth = 100;
self.navigationOutlineView.contentViewPreferredHeight = 100;
self.navigationOutlineView.expandParentOnDoubleClick = YES;
[self.navigationOutlineView expandItem:navigationTreeMatrix[0]];
}
- (void)populateEncodings
{
[self.primaryEncodingButton removeAllItems];
[self.fallbackEncodingButton removeAllItems];
/* Build list of encodings */
self.encodingList = [NSString supportedStringEncodingsWithTitle:NO];
NSArray *encodingNames = self.encodingList.sortedDictionaryKeys;
/* What we are basically doing now is sorting all the encodings, then removing
UTF-8 from the sorted list and inserting it at the top of the list. */
NSString *utf8title = [NSString localizedNameOfStringEncoding:NSUTF8StringEncoding];
NSMutableArray *encodingsToAdd = [encodingNames mutableCopy];
[encodingsToAdd removeObject:utf8title];
[self.primaryEncodingButton addItemWithTitle:utf8title];
[self.fallbackEncodingButton addItemWithTitle:utf8title];
/* Add the encodings to the popup list. This for loop will find the first
parentheses opening and compare everything before it to the one found for
the previous encoding. If the prefix has changed, then a separator is
inserted. This groups the encodings.*/
/* We do this two times. The first time setups up preferred encodings at
the top of the list. The next handles everything else. */
NSArray *favoredEncodings = @[@"Unicode", @"Western", @"Central European"];
[self populateEncodingPopup:encodingsToAdd preferredEncodings:favoredEncodings ignoreFavored:NO];
if ([RZUserDefaults() boolForKey:@"Server Properties Window Sheet -> Include Advanced Encodings"]) {
[self populateEncodingPopup:encodingsToAdd preferredEncodings:favoredEncodings ignoreFavored:YES];
}
}
- (void)populateEncodingPopup:(NSArray *)encodingsToAdd preferredEncodings:(NSArray *)favoredEncodings ignoreFavored:(BOOL)ignoreFavored
{
NSString *encodingPrefixPrevious = nil;
for (NSString *encoding in encodingsToAdd) {
NSInteger parenthesisPosition = [encoding stringPosition:@" ("];
if (parenthesisPosition <= 0) {
continue;
}
NSString *encodingPrefix = [encoding substringToIndex:parenthesisPosition];
if (ignoreFavored && [favoredEncodings containsObject:encodingPrefix]) {
continue;
} else if (ignoreFavored == NO && [favoredEncodings containsObject:encodingPrefix] == NO) {
continue;
}
if ([encodingPrefix isEqualToString:encodingPrefixPrevious] == NO) {
encodingPrefixPrevious = encodingPrefix;
[self.primaryEncodingButton.menu addItem:[NSMenuItem separatorItem]];
[self.fallbackEncodingButton.menu addItem:[NSMenuItem separatorItem]];
}
[self.primaryEncodingButton addItemWithTitle:encoding];
[self.fallbackEncodingButton addItemWithTitle:encoding];
}
}
#pragma mark -
#pragma mark Initialization Handler
- (void)start
{
[self startWithSelection:TDCServerPropertiesSheetSelectionDefault context:nil];
}
- (void)startWithSelection:(TDCServerPropertiesSheetSelection)selection context:(nullable id)context
{
[self startSheet];
[self navigateToSelection:selection];
switch (selection) {
case TDCServerPropertiesSheetSelectionNewIgnoreEntry:
{
if ([context isKindOfClass:[NSString class]]) {
[self addIgnoreAddressBookEntryWithHostmask:context];
} else if ([context isKindOfClass:[IRCAddressBookEntry class]]) {
[self editAddressBookEntryWithObject:context];
}
break;
}
default:
{
break;
}
}
}
- (void)navigateToSelection:(TDCServerPropertiesSheetSelection)selection
{
if (selection == TDCServerPropertiesSheetSelectionDefault) {
selection = TDCServerPropertiesSheetSelectionGeneral;
} else if (selection == TDCServerPropertiesSheetSelectionNewIgnoreEntry) {
selection = TDCServerPropertiesSheetSelectionAddressBook;
}
[self.navigationOutlineView navigateToItemWithIdentifier:selection];
[self.sheet recalculateKeyViewLoop];
}
- (void)closeChildSheets
{
if (self.addressBookSheet) {
[self.addressBookSheet close];
} else if (self.channelSheet) {
[self.channelSheet close];
} else if (self.highlightSheet) {
[self.highlightSheet close];
} else if (self.serverEndpointSheet) {
[self.serverEndpointSheet close];
} else if (self.clientCertificateSelectCertificatePanel) {
[NSApp stopModalWithCode:NSModalResponseCancel];
}
}
- (void)ok:(id)sender
{
if ([self okOrError] == NO) {
return;
}
[self removeConfigurationDidChangeObserver];
[self closeChildSheets];
[self clearChannelListPredicate];
[self saveConfig];
if ([self.delegate respondsToSelector:@selector(serverPropertiesSheet:onOk:)]) {
[self.delegate serverPropertiesSheet:self onOk:[self.config copy]];
}
[super ok:nil];
}
- (BOOL)okOrError
{
TDCServerPropertiesSheetSelection selection = self.navigationOutlineView.selectedItem.identifier;
if ([self okOrErrorForSelection:selection] == NO) {
return NO;
}
/* We want to show the error for the visible view first so that
the user isn't jerked around. To accomplish this, we keep an
array of views in which error occurs. Check error in visible
view, remove that from array, then enumerate the rest. */
NSMutableArray *remainingSelections =
[@[
@(TDCServerPropertiesSheetSelectionGeneral),
@(TDCServerPropertiesSheetSelectionIdentity),
@(TDCServerPropertiesSheetSelectionDisconnectMessages),
@(TDCServerPropertiesSheetSelectionProxyServer),
] mutableCopy];
[remainingSelections removeObject:@(selection)];
for (NSNumber *selectionRemaining in remainingSelections) {
if ([self okOrErrorForSelection:selectionRemaining.integerValue] == NO) {
return NO;
}
}
return YES;
}
- (BOOL)okOrErrorForSelection:(TDCServerPropertiesSheetSelection)selection
{
switch (selection) {
case TDCServerPropertiesSheetSelectionGeneral:
{
if ([self okOrErrorForTextField:self.connectionNameTextField inSelection:selection] == NO) {
return NO;
} else if ([self okOrErrorForComboBox:self.serverAddressComboBox inSelection:selection] == NO) {
return NO;
} else if ([self okOrErrorForTextField:self.serverPortTextField inSelection:selection] == NO) {
return NO;
}
break;
}
case TDCServerPropertiesSheetSelectionIdentity:
{
if ([self okOrErrorForTextField:self.nicknameTextField inSelection:selection] == NO) {
return NO;
} else if ([self okOrErrorForTextField:self.awayNicknameTextField inSelection:selection] == NO) {
return NO;
} else if ([self okOrErrorForTextField:self.alternateNicknamesTextField inSelection:selection] == NO) {
return NO;
} else if ([self okOrErrorForTextField:self.usernameTextField inSelection:selection] == NO) {
return NO;
} else if ([self okOrErrorForTextField:self.realNameTextField inSelection:selection] == NO) {
return NO;
}
break;
}
case TDCServerPropertiesSheetSelectionDisconnectMessages:
{
if ([self okOrErrorForTextField:self.normalLeavingCommentTextField inSelection:selection] == NO) {
return NO;
} else if ([self okOrErrorForTextField:self.sleepModeQuitMessageTextField inSelection:selection] == NO) {
return NO;
}
break;
}
case TDCServerPropertiesSheetSelectionProxyServer:
{
if ([self okOrErrorForTextField:self.proxyAddressTextField inSelection:selection] == NO) {
return NO;
} else if ([self okOrErrorForTextField:self.proxyPortTextField inSelection:selection] == NO) {
return NO;
}
break;
}
default:
{
break;
}
} // switch()
return YES;
}
- (BOOL)okOrErrorForComboBox:(TVCValidatedComboBox *)comboBox inSelection:(TDCServerPropertiesSheetSelection)selection
{
if (comboBox.valueIsValid) {
return YES;
}
[self navigateToSelection:selection];
XRPerformBlockAsynchronouslyOnMainQueue(^{
[comboBox showValidationErrorPopover];
});
return NO;
}
- (BOOL)okOrErrorForTextField:(TVCValidatedTextField *)textField inSelection:(TDCServerPropertiesSheetSelection)selection
{
if (textField.valueIsValid) {
return YES;
}
[self navigateToSelection:selection];
/* Give navigation time to settle before trying to attach popover */
XRPerformBlockAsynchronouslyOnMainQueue(^{
[textField showValidationErrorPopover];
});
return NO;
}
- (void)cancel:(id)sender
{
[self removeConfigurationDidChangeObserver];
[self closeChildSheets];
[super cancel:nil];
}
- (void)addConfigurationDidChangeObserver
{
if (self.client == nil) {
return;
}
[RZNotificationCenter() addObserver:self
selector:@selector(underlyingConfigurationChanged:)
name:IRCClientConfigurationWasUpdatedNotification
object:self.client];
}
- (void)removeConfigurationDidChangeObserver
{
[RZNotificationCenter() removeObserver:self];
}
- (void)underlyingConfigurationChanged:(NSNotification *)notification
{
IRCClient *client = notification.object;
NSWindow *window = self.sheet.deepestWindow;
[TDCAlert alertSheetWithWindow:window
body:TXTLS(@"TDCServerPropertiesSheet[oz4-kb]")
title:TXTLS(@"TDCServerPropertiesSheet[bzh-il]")
defaultButton:TXTLS(@"Prompts[mvh-ms]")
alternateButton:TXTLS(@"Prompts[99q-gg]")
otherButton:nil
completionBlock:^(TDCAlertResponse buttonClicked, BOOL suppressed, id underlyingAlert) {
if (buttonClicked != TDCAlertResponseDefault) {
return;
}
[self close];
[client updateStoredConfiguration];
self.config = [client.config mutableCopy];
[self loadConfig];
[self start];
}];
}
- (void)loadConfig
{
/* General */
self.connectionNameTextField.stringValue = self.config.connectionName;
self.autoConnectCheck.state = self.config.autoConnect;
self.autoReconnectCheck.state = self.config.autoReconnect;
self.autoDisconnectOnSleepCheck.state = self.config.autoSleepModeDisconnect;
/* ZNC Bouncer */
self.zncIgnoreConfiguredAutojoinCheck.state = self.config.zncIgnoreConfiguredAutojoin;
self.zncIgnorePlaybackNotificationsCheck.state = self.config.zncIgnorePlaybackNotifications;
self.zncOnlyPlaybackLatestCheck.state = self.config.zncOnlyPlaybackLatest;
/* Network Socket */
IRCConnectionAddressType addressType = self.config.addressType;
self.connectionIPv4AddressTypeCheck.state = (addressType == IRCConnectionAddressTypeIPv4);
self.connectionIPv6AddressTypeCheck.state = (addressType == IRCConnectionAddressTypeIPv6);
self.connectionDefaultAddressTypeCheck.state = (addressType == IRCConnectionAddressTypeDefault);
self.pongTimerCheck.state = self.config.performPongTimer;
self.performDisconnectOnPongTimerCheck.state = self.config.performDisconnectOnPongTimer;
self.disconnectOnReachabilityChangeCheck.state = self.config.performDisconnectOnReachabilityChange;
self.validateServerCertificateChainCheck.state = self.config.validateServerCertificateChain;
[self.preferredCipherSuitesButton selectItemWithTag:self.config.cipherSuites];
/* Identity */
if (self.config.nickname.length > 0) {
self.nicknameTextField.stringValue = self.config.nickname;
} else {
self.nicknameTextField.stringValue = [TPCPreferences defaultNickname];
}
self.awayNicknameTextField.stringValue = self.config.awayNickname;
NSString *alternateNicknamesString = [self.config.alternateNicknames componentsJoinedByString:@" "];
self.alternateNicknamesTextField.stringValue = alternateNicknamesString;
if (self.config.username.length > 0) {
self.usernameTextField.stringValue = self.config.username;
} else {
self.usernameTextField.stringValue = [TPCPreferences defaultUsername];
}
if (self.config.realName.length > 0) {
self.realNameTextField.stringValue = self.config.realName;
} else {
self.realNameTextField.stringValue = [TPCPreferences defaultRealName];
}
self.nicknamePasswordTextField.stringValue = self.config.nicknamePassword;
self.autojoinWaitsForNickServCheck.state = self.config.autojoinWaitsForNickServ;
self.hideAutojoinDelayedWarningsCheck.state = (self.config.hideAutojoinDelayedWarnings == NO);
/* Messages */
self.normalLeavingCommentTextField.stringValue = self.config.normalLeavingComment;
self.sleepModeQuitMessageTextField.stringValue = self.config.sleepModeLeavingComment;
/* Encoding */
NSString *primaryEncodingTitle = [self.encodingList firstKeyForObject:@(self.config.primaryEncoding)];
[self.primaryEncodingButton selectItemWithTitle:primaryEncodingTitle];
NSString *fallbackEncodingTitle = [self.encodingList firstKeyForObject:@(self.config.fallbackEncoding)];
[self.fallbackEncodingButton selectItemWithTitle:fallbackEncodingTitle];
/* Proxy Server */
[self.proxyTypeButton selectItemWithTag:self.config.proxyType];
self.proxyAddressTextField.stringValue = self.config.proxyAddress;
self.proxyPortTextField.integerValue = self.config.proxyPort;
self.proxyUsernameTextField.stringValue = self.config.proxyUsername;
self.proxyPasswordTextField.stringValue = self.config.proxyPassword;
/* Connect Commands */
NSString *loginCommandsString = [self.config.loginCommands componentsJoinedByString:@"\n"];
self.connectCommandsField.string = loginCommandsString;
self.setInvisibleModeOnConnectCheck.state = self.config.setInvisibleModeOnConnect;
/* Flood Control */
self.floodControlDelayTimerSliderTempValue = self.config.floodControlDelayTimerInterval;
self.floodControlMessageCountSliderTempValue = self.config.floodControlMaximumMessages;
/* Mutable Stores */
[self.addressBookArrayController addObjects:self.config.ignoreList];
[self.channelListArrayController addObjects:self.config.channelList];
[self.highlightListArrayController addObjects:self.config.highlightList];
[self.serverListArrayController addObjects:self.config.serverList];
/* Special loads */
[self loadPrimaryServerEndpoint];
[self loadConfigPostflight];
}
- (void)loadPrimaryServerEndpoint
{
IRCServer *server = self.serverList.firstObject;
if (server == nil) {
self.serverAddressComboBox.stringValue = @"";
self.serverPortTextField.integerValue = IRCConnectionDefaultServerPort;
self.prefersSecuredConnectionCheck.state = NSControlStateValueOff;
self.serverPasswordTextField.stringValue = @"";
return;
}
self.populatingPrimaryServer = YES;
NSString *serverAddress = server.serverAddress;
if (serverAddress) {
IRCNetwork *serverAddressNetwork = [self.networkList networkWithServerAddress:serverAddress];
if (serverAddressNetwork) {
self.serverAddressComboBox.stringValue = serverAddressNetwork.networkName;
} else {
self.serverAddressComboBox.stringValue = serverAddress;
}
}
self.serverPortTextField.integerValue = server.serverPort;
self.prefersSecuredConnectionCheck.state = server.prefersSecuredConnection;
self.serverPasswordTextField.stringValue = server.serverPassword;
self.populatingPrimaryServer = NO;
}
- (void)loadConfigPostflight
{
[self setChannelListPredicate];
[self updateAddressBookPage];
[self updateChannelListPage];
[self updateClientCertificatePage];
[self updateHighlightsPage];
[self updateIdentityPage];
[self preferredCipherSuitesChanged:nil];
[self proxyTypeChanged:nil];
}
- (void)saveConfig
{
/* General */
self.config.connectionName = self.connectionNameTextField.value;
self.config.autoConnect = (self.autoConnectCheck.state == NSControlStateValueOn);
self.config.autoReconnect = (self.autoReconnectCheck.state == NSControlStateValueOn);
self.config.autoSleepModeDisconnect = (self.autoDisconnectOnSleepCheck.state == NSControlStateValueOn);
/* ZNC Bouncer */
self.config.zncIgnoreConfiguredAutojoin = (self.zncIgnoreConfiguredAutojoinCheck.state == NSControlStateValueOn);
self.config.zncIgnorePlaybackNotifications = (self.zncIgnorePlaybackNotificationsCheck.state == NSControlStateValueOn);
self.config.zncOnlyPlaybackLatest = (self.zncOnlyPlaybackLatestCheck.state == NSControlStateValueOn);
/* Network Socket */
self.config.performPongTimer = (self.pongTimerCheck.state == NSControlStateValueOn);
self.config.performDisconnectOnPongTimer = (self.performDisconnectOnPongTimerCheck.state == NSControlStateValueOn);
self.config.performDisconnectOnReachabilityChange = (self.disconnectOnReachabilityChangeCheck.state == NSControlStateValueOn);
self.config.validateServerCertificateChain = (self.validateServerCertificateChainCheck.state == NSControlStateValueOn);
self.config.cipherSuites = self.preferredCipherSuitesButton.selectedTag;
/* Identity */
self.config.nickname = self.nicknameTextField.value;
self.config.username = self.usernameTextField.value;
self.config.realName = self.realNameTextField.value;
self.config.awayNickname = self.awayNicknameTextField.value;
self.config.nicknamePassword = self.nicknamePasswordTextField.trimmedStringValue;
self.config.autojoinWaitsForNickServ = (self.autojoinWaitsForNickServCheck.state == NSControlStateValueOn);
self.config.hideAutojoinDelayedWarnings = (self.hideAutojoinDelayedWarningsCheck.state != NSControlStateValueOn);
/* Alternate nicknames */
NSString *alternateNicknamesString = self.alternateNicknamesTextField.value;
NSArray *alternateNicknames = [alternateNicknamesString componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
self.config.alternateNicknames = [alternateNicknames arrayByRemovingEmptyValuesAndUniquing];
/* Messages */
self.config.sleepModeLeavingComment = self.sleepModeQuitMessageTextField.value;
self.config.normalLeavingComment = self.normalLeavingCommentTextField.value;
/* Encoding */
NSStringEncoding primaryEncoding = [self.encodingList unsignedIntegerForKey:self.primaryEncodingButton.title];
self.config.primaryEncoding = primaryEncoding;
NSStringEncoding fallbackEncoding = [self.encodingList unsignedIntegerForKey:self.fallbackEncodingButton.title];
self.config.fallbackEncoding = fallbackEncoding;
/* Proxy Server */
self.config.proxyType = self.proxyTypeButton.selectedTag;
self.config.proxyAddress = self.proxyAddressTextField.lowercaseValue;
self.config.proxyPort = self.proxyPortTextField.integerValue;
self.config.proxyUsername = self.proxyUsernameTextField.trimmedFirstTokenStringValue;
self.config.proxyPassword = self.proxyPasswordTextField.trimmedStringValue;
/* Connect Commands */
NSString *connectCommandsString = self.connectCommandsField.string;
NSArray *connectCommands = [connectCommandsString componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]];
self.config.loginCommands = [connectCommands arrayByRemovingEmptyValues:YES trimming:YES uniquing:NO];
self.config.setInvisibleModeOnConnect = (self.setInvisibleModeOnConnectCheck.state == NSControlStateValueOn);
/* Flood Control */
self.config.floodControlMaximumMessages = self.floodControlMessageCountSlider.integerValue;
self.config.floodControlDelayTimerInterval = self.floodControlDelayTimerSlider.integerValue;
/* Mutable stores. */
self.config.channelList = self.channelListArrayController.arrangedObjects;
self.config.highlightList = self.highlightListArrayController.arrangedObjects;
self.config.ignoreList = self.addressBookArrayController.arrangedObjects;
self.config.serverList = self.serverListArrayController.arrangedObjects;
}
- (void)restorePreviousValuesForPrimaryServer
{
IRCServer *previousServer = self.previousPrimaryServer;
if (previousServer == nil) {
return;
}
self.populatingPrimaryServer = YES;
self.serverPortTextField.integerValue = previousServer.serverPort;
self.prefersSecuredConnectionCheck.state = previousServer.prefersSecuredConnection;
self.previousPrimaryServer = nil;
self.populatingPrimaryServer = NO;
}
- (void)saveCurrentValuesForPrimaryServer
{
/* Do not change the previous primary server between predefined servers. */
if (self.previousPrimaryServer != nil) {
return;
}
IRCServer *server = self.serverList.firstObject;
if (server) {
self.previousPrimaryServer = server;
return;
}
IRCServerMutable *serverMutable = [IRCServerMutable new];
serverMutable.serverPort = self.serverPortTextField.integerValue;
serverMutable.prefersSecuredConnection = (self.prefersSecuredConnectionCheck.state == NSControlStateValueOn);
self.previousPrimaryServer = serverMutable;
}
- (void)populateDefaultsForPreconfiguredNetwork
{
if (self.populatingPrimaryServer) {
return;
}
NSString *serverAddress = self.serverAddressComboBox.value;
if ([serverAddress isEqualToString:self.lastServerAddressValue]) {
return;
}
self.lastServerAddressValue = serverAddress;
IRCNetwork *network = [self.networkList networkNamed:serverAddress];
if (network == nil) {
network = [self.networkList networkWithServerAddress:serverAddress];
}
if (network == nil) {
[self restorePreviousValuesForPrimaryServer];
return;
}
self.populatingPrimaryServer = YES;
/* The predefined list in the combo box is only the network name.
IRCNetwork is also capable of matching known server addresses.
If we have a known network but it's not a predefined value,
then it very might be a server address. */
/* Let's replace the given input that matches a network with the
network name itself. */
if (self.serverAddressComboBox.valueIsPredefined == NO) {
NSString *networkName = network.networkName;
self.serverAddressComboBox.stringValue = networkName;
self.lastServerAddressValue = networkName;
}
/* Populate other defaults */
[self saveCurrentValuesForPrimaryServer];
self.serverPortTextField.integerValue = network.serverPort;
self.prefersSecuredConnectionCheck.state = (network.prefersSecuredConnection == NSControlStateValueOn);
self.populatingPrimaryServer = NO;
}
- (void)updateChannelListPage
{
NSInteger selectedRow = self.channelListTable.selectedRow;
self.deleteChannelButton.enabled = (selectedRow >= 0);
self.editChannelButton.enabled = (selectedRow >= 0);
}
- (void)clearChannelListPredicate
{
self.channelListArrayController.filterPredicate = nil;
}
- (void)setChannelListPredicate
{
self.channelListArrayController.filterPredicate =
[NSPredicate predicateWithFormat:@"type == 0"]; // Is channel type
}
- (void)updateAddressBookPage
{
NSInteger selectedRow = self.addressBookTable.selectedRow;
self.deleteAddressBookEntryButton.enabled = (selectedRow >= 0);
self.editAddressBookEntryButton.enabled = (selectedRow >= 0);
}
- (void)updateHighlightsPage
{
NSInteger selectedRow = self.highlightsTable.selectedRow;
self.deleteHighlightButton.enabled = (selectedRow >= 0);
self.editHighlightButton.enabled = (selectedRow >= 0);
}
- (void)useSSLCheckChanged:(id)sender
{
NSInteger serverPort = self.serverPortTextField.integerValue;
BOOL useSSL = (self.prefersSecuredConnectionCheck.state == NSControlStateValueOn);
if (useSSL) {
if (serverPort == 6667) {
self.serverPortTextField.stringValue = TXLocalizationNotNeeded(@"6697");
}
} else {
if (serverPort == 6697) {
self.serverPortTextField.stringValue = TXLocalizationNotNeeded(@"6667");
}
}
[self rebuildMutableServerEndpointListIfNeeded:sender];
}
- (void)updateIdentityPage
{
self.hideAutojoinDelayedWarningsCheck.hidden =
(self.autojoinWaitsForNickServCheck.state == NSControlStateValueOff);
}
#pragma mark -
#pragma mark Properties
- (NSArray *)addressBookList
{
return self.addressBookArrayController.arrangedObjects;
}
- (NSArray *)channelList
{
return self.channelListArrayController.arrangedObjects;
}
- (NSArray *)highlightList
{
return self.highlightListArrayController.arrangedObjects;
}
- (NSArray *)serverList
{
return self.serverListArrayController.arrangedObjects;
}
#pragma mark -
#pragma mark Delegates
- (void)controlTextDidChange:(NSNotification *)notification
{
NSControl *sender = notification.object;
if (sender == self.serverPasswordTextField) {
[self rebuildMutableServerEndpointListIfNeeded:sender];
}
}
- (void)validatedTextFieldTextDidChange:(id)sender
{
if (sender == self.serverAddressComboBox) {
[self populateDefaultsForPreconfiguredNetwork];
[self rebuildMutableServerEndpointListIfNeeded:sender];
} else if (sender == self.serverPortTextField) {
[self rebuildMutableServerEndpointListIfNeeded:sender];
}
}
#pragma mark -
#pragma mark Actions
- (void)autojoinWaitsForNickServChanged:(id)sender
{
[self updateIdentityPage];
if (self.autojoinWaitsForNickServCheck.state != NSControlStateValueOn) {
return;
}
if (self.nicknamePasswordTextField.stringValue.length > 0 ||
self.clientCertificateResetCertificateButton.enabled)
{
return;
}
[TDCAlert modalAlertWithMessage:TXTLS(@"TDCServerPropertiesSheet[26u-j8]")
title:TXTLS(@"TDCServerPropertiesSheet[94r-eq]")
defaultButton:TXTLS(@"Prompts[c7s-dq]")
alternateButton:nil];
}
- (void)preferredCipherSuitesChanged:(id)sender
{
NSInteger cipherSuites = self.preferredCipherSuitesButton.selectedTag;
self.viewListOfPreferredCipherSuitesButton.enabled =
(cipherSuites != RCMCipherSuiteCollectionNone);
}
- (void)preferredCipherSuitesViewList:(id)sender
{
NSInteger cipherSuites = self.preferredCipherSuitesButton.selectedTag;
NSArray *cipherSuitesDescriptions = [RCMSecureTransport descriptionsForCipherListCollection:cipherSuites withProtocol:YES];
NSString *cipherSuitesDescription = [cipherSuitesDescriptions componentsJoinedByString:@"\n"];
NSString *cipherSuitesTitle = self.preferredCipherSuitesButton.titleOfSelectedItem;
[TDCAlert alertSheetWithWindow:self.sheet
body:TXTLS(@"TDCServerPropertiesSheet[k50-8n]", cipherSuitesDescription)
title:TXTLS(@"TDCServerPropertiesSheet[yko-5g]", cipherSuitesTitle)
defaultButton:TXTLS(@"Prompts[c7s-dq]")
alternateButton:nil
otherButton:nil];
}
- (void)proxyTypeChanged:(id)sender
{
NSInteger proxyType = self.proxyTypeButton.selectedTag;
BOOL isSystemSocksProxyEnabled = (proxyType == IRCConnectionProxyTypeAutomatic);
BOOL isTorBrowserProxyEnabled = (proxyType == IRCConnectionProxyTypeTor);
BOOL supportsAuthentication = (proxyType == IRCConnectionProxyTypeSocks5);
BOOL httpsEnabled = (proxyType == IRCConnectionProxyTypeHTTP || proxyType == IRCConnectionProxyTypeHTTPS);
BOOL socksEnabled = (proxyType == IRCConnectionProxyTypeSocks4 || proxyType == IRCConnectionProxyTypeSocks5);
BOOL enabled = (httpsEnabled || socksEnabled);
self.contentViewProxyServerInputView.hidden = (httpsEnabled == NO && socksEnabled == NO);
self.contentViewProxyServerTorBrowserView.hidden = (isTorBrowserProxyEnabled == NO);
self.contentViewProxyServerSystemSocksView.hidden = (isSystemSocksProxyEnabled == NO);
self.proxyAddressTextField.enabled = enabled;
self.proxyPortTextField.enabled = enabled;
self.proxyUsernameTextField.enabled = (socksEnabled && supportsAuthentication);
self.proxyPasswordTextField.enabled = (socksEnabled && supportsAuthentication);
[self.proxyAddressTextField performValidation];
[self.proxyPortTextField performValidation];
}
- (void)openProxySettingsInSystemPreferences:(id)sender
{
[TDCPreferencesController openProxySettingsInSystemPreferences];
}
- (void)toggleAdvancedEncodings:(id)sender
{
NSString *primaryEncoding = self.primaryEncodingButton.titleOfSelectedItem;
NSString *fallbackEncoding = self.fallbackEncodingButton.titleOfSelectedItem;
[self populateEncodings];
NSMenuItem *primaryEncodingItem = nil;
if (primaryEncoding) {
primaryEncodingItem = [self.primaryEncodingButton itemWithTitle:primaryEncoding];
}
if (primaryEncodingItem == nil) {
primaryEncoding = [NSString localizedNameOfStringEncoding:TXDefaultPrimaryStringEncoding];
}
NSMenuItem *fallbackEncodingItem = nil;
if (fallbackEncoding) {
fallbackEncodingItem = [self.fallbackEncodingButton itemWithTitle:fallbackEncoding];
}
if (fallbackEncodingItem == nil) {
fallbackEncoding = [NSString localizedNameOfStringEncoding:TXDefaultFallbackStringEncoding];
}
[self.primaryEncodingButton selectItemWithTitle:primaryEncoding];
[self.fallbackEncodingButton selectItemWithTitle:fallbackEncoding];
}
- (void)preferredInternetProtocolChanged:(id)sender
{
TEXTUAL_IGNORE_DEPRECATION_BEGIN
/* Changing the property triggers a deprecation log to console
which is just unnecessary output when each time we change it. */
if (self.config.connectionPrefersIPv4) {
self.config.connectionPrefersIPv4 = NO;
}
TEXTUAL_IGNORE_DEPRECATION_END
self.config.addressType = [sender tag];
}
#pragma mark -
#pragma mark SSL Certificate
- (void)onClientCertificateFingerprintSHA512CopyRequested:(id)sender
{
NSString *fingerprint = self.clientCertificateSHA512FingerprintField.stringValue;
NSString *command = [NSString stringWithFormat:@"/msg NickServ cert add %@", fingerprint];
RZPasteboard().stringContent = command;
}
- (void)onClientCertificateFingerprintSHA2CopyRequested:(id)sender
{
NSString *fingerprint = self.clientCertificateSHA2FingerprintField.stringValue;
NSString *command = [NSString stringWithFormat:@"/msg NickServ cert add %@", fingerprint];
RZPasteboard().stringContent = command;
}
- (void)onClientCertificateFingerprintSHA1CopyRequested:(id)sender
{
NSString *fingerprint = self.clientCertificateSHA1FingerprintField.stringValue;
NSString *command = [NSString stringWithFormat:@"/msg NickServ cert add %@", fingerprint];
RZPasteboard().stringContent = command;
}
- (void)onClientCertificateFingerprintMD5CopyRequested:(id)sender
{
NSString *fingerprint = self.clientCertificateMD5FingerprintField.stringValue;
NSString *command = [NSString stringWithFormat:@"/msg NickServ cert add %@", fingerprint];
RZPasteboard().stringContent = command;
}
- (void)readClientCertificateCommonName:(NSString **)commonNameOut
sha512Fingerprint:(NSString **)sha512FingerprintOut
sha2Fingerprint:(NSString **)sha2FingerprintOut
sha1Fingerprint:(NSString **)sha1FingerprintOut
md5Fingerprint:(NSString **)md5FingerprintOut
{
NSData *certificateDataIn = self.config.identityClientSideCertificate;
if (certificateDataIn == nil) {
return;
}
/* ====================================== */
SecKeychainItemRef certificateRef;
CFDataRef certificateDataInRef = (__bridge CFDataRef)certificateDataIn;
OSStatus status = SecKeychainItemCopyFromPersistentReference(certificateDataInRef, &certificateRef);
if (status != noErr) {
return;
}
/* ====================================== */
CFStringRef commonNameRef;
status = SecCertificateCopyCommonName((SecCertificateRef)certificateRef, &commonNameRef);
if (status != noErr) {
CFRelease(certificateRef);
return;
}
*commonNameOut = (__bridge NSString *)(commonNameRef);
CFRelease(commonNameRef);
/* ====================================== */
CFDataRef certificateDataRef = SecCertificateCopyData((SecCertificateRef)certificateRef);
if (certificateDataRef) {
NSData *certificateData = (__bridge NSData *)certificateDataRef;
*sha512FingerprintOut = certificateData.sha512;
*sha2FingerprintOut = certificateData.sha256;
*sha1FingerprintOut = certificateData.sha1;
*md5FingerprintOut = certificateData.md5;
CFRelease(certificateDataRef);
}
/* ====================================== */
CFRelease(certificateRef);
}
- (void)saveClientCertificateWithIdentity:(SecIdentityRef)identityInRef
{
if (identityInRef == NULL) {
return;
}
/* ====================================== */
SecCertificateRef certificateRef;
OSStatus status = SecIdentityCopyCertificate(identityInRef, &certificateRef);
if (status != noErr) {
LogToConsoleError("Operation Failed (2): %{public}i", status);
return;
}
/* ====================================== */
CFDataRef certificateDataRef;
status = SecKeychainItemCreatePersistentReference((SecKeychainItemRef)certificateRef, &certificateDataRef);
if (status != noErr) {
CFRelease(certificateRef);
LogToConsoleError("Operation Failed (3): %{public}i", status);
return;
}
/* ====================================== */
self.config.identityClientSideCertificate = (__bridge NSData *)certificateDataRef;
if (self.prefersSecuredConnectionCheck.state == NSControlStateValueOff) {
self.prefersSecuredConnectionCheck.state = NSControlStateValueOn;
[self useSSLCheckChanged:nil];
}
/* ====================================== */
CFRelease(certificateRef);
CFRelease(certificateDataRef);
}
- (void)updateClientCertificatePage
{
NSString *commonName = nil;
NSString *sha512Fingerprint = nil;
NSString *sha2Fingerprint = nil;
NSString *sha1Fingerprint = nil;
NSString *md5Fingerprint = nil;
[self readClientCertificateCommonName:&commonName
sha512Fingerprint:&sha512Fingerprint
sha2Fingerprint:&sha2Fingerprint
sha1Fingerprint:&sha1Fingerprint
md5Fingerprint:&md5Fingerprint];
BOOL hasNoCertificate = (commonName.length == 0);
if (hasNoCertificate) {
self.clientCertificateCommonNameField.stringValue = TXTLS(@"TDCServerPropertiesSheet[6xz-ec]");
self.clientCertificateSHA512FingerprintField.stringValue = TXTLS(@"TDCServerPropertiesSheet[6xz-ec]");
self.clientCertificateSHA2FingerprintField.stringValue = TXTLS(@"TDCServerPropertiesSheet[6xz-ec]");
self.clientCertificateSHA1FingerprintField.stringValue = TXTLS(@"TDCServerPropertiesSheet[6xz-ec]");
self.clientCertificateMD5FingerprintField.stringValue = TXTLS(@"TDCServerPropertiesSheet[6xz-ec]");
} else {
self.clientCertificateCommonNameField.stringValue = commonName;
self.clientCertificateSHA512FingerprintField.stringValue = sha512Fingerprint.uppercaseString;
self.clientCertificateSHA2FingerprintField.stringValue = sha2Fingerprint.uppercaseString;
self.clientCertificateSHA1FingerprintField.stringValue = sha1Fingerprint.uppercaseString;
self.clientCertificateMD5FingerprintField.stringValue = md5Fingerprint.uppercaseString;
}
self.clientCertificateResetCertificateButton.enabled = (hasNoCertificate == NO);
self.clientCertificateSHA512FingerprintCopyButton.enabled = (hasNoCertificate == NO);
self.clientCertificateSHA2FingerprintCopyButton.enabled = (hasNoCertificate == NO);
self.clientCertificateSHA1FingerprintCopyButton.enabled = (hasNoCertificate == NO);
self.clientCertificateMD5FingerprintCopyButton.enabled = (hasNoCertificate == NO);
}
- (void)onClientCertificateResetRequested:(id)sender
{
self.config.identityClientSideCertificate = nil;
[self updateClientCertificatePage];
}
- (void)onClientCertificateChangeRequested:(id)sender
{
CFArrayRef identities = NULL;
NSDictionary *queryFlags = @{
(id)kSecClass : (id)kSecClassIdentity,
(id)kSecMatchLimit : (id)kSecMatchLimitAll,
(id)kSecReturnRef : (id)kCFBooleanTrue
};
OSStatus queryStatus = SecItemCopyMatching((__bridge CFDictionaryRef)queryFlags, (CFTypeRef *)&identities);
if (queryStatus != noErr) {
LogToConsoleError("Operation Failed (1): %{public}i", queryStatus);
}
if (identities == NULL || CFArrayGetCount(identities) == 0) {
[TDCAlert alertWithMessage:TXTLS(@"TDCServerPropertiesSheet[489-hG]")
title:TXTLS(@"TDCServerPropertiesSheet[pmk-os]")
defaultButton:TXTLS(@"Prompts[c7s-dq]")
alternateButton:nil
otherButton:TXTLS(@"TDCServerPropertiesSheet[3ju-lo]")
completionBlock:^(TDCAlertResponse buttonClicked, BOOL suppressed, id underlyingAlert) {
if (buttonClicked == TDCAlertResponseOther) {
[TLOpenLink openWithString:@"https://help.codeux.com/textual/Using-CertFP.kb" inBackground:NO];
}
}];
return;
}
SFChooseIdentityPanel *panel = [SFChooseIdentityPanel sharedChooseIdentityPanel];
self.clientCertificateSelectCertificatePanel = panel;
[panel setInformativeText:TXTLS(@"TDCServerPropertiesSheet[mi4-fd]")];
[panel setAlternateButtonTitle:TXTLS(@"Prompts[qso-2g]")];
NSInteger panelResponse =
[panel runModalForIdentities:(__bridge NSArray *)(identities)
message:TXTLS(@"TDCServerPropertiesSheet[6wq-i4]")];
CFRelease(identities);
if (panelResponse == NSModalResponseOK) {
SecIdentityRef identity = [panel identity];
[self saveClientCertificateWithIdentity:identity];
[self updateClientCertificatePage];
}
self.clientCertificateSelectCertificatePanel = nil;
}
#pragma mark -
#pragma mark Redundancy
- (void)editSeverEndpoints:(id)sender
{
TDCServerEndpointListSheet *sheet = [[TDCServerEndpointListSheet alloc] initWithWindow:self.sheet];
sheet.delegate = self;
[sheet startWithServerList:self.serverList];
self.serverEndpointSheet = sheet;
}
- (void)serverEndpointListSheet:(TDCServerEndpointListSheet *)ender onOk:(NSArray *)serverList
{
[self.serverListArrayController removeAllArrangedObjects];
[self.serverListArrayController addObjects:serverList];
[self loadPrimaryServerEndpoint];
}
- (void)serverEndpointListSheetWillClose:(TDCServerEndpointListSheet *)sender
{
self.serverEndpointSheet = nil;
}
- (void)rebuildMutableServerEndpointList:(id)sender
{
NSParameterAssert(sender != nil);
if (self.populatingPrimaryServer) {
return;
}
IRCServer *server = self.serverList.firstObject;
IRCServerMutable *serverMutable = nil;
if (server == nil) {
serverMutable = [IRCServerMutable new];
} else {
serverMutable = [server mutableCopy];
}
{
NSString *serverAddress = self.serverAddressComboBox.value;
IRCNetwork *serverAddressNetwork = [self.networkList networkNamed:serverAddress];
if (serverAddressNetwork) {
serverMutable.serverAddress = serverAddressNetwork.serverAddress;
} else {
serverMutable.serverAddress = serverAddress.lowercaseString;
}
}
serverMutable.serverPort = self.serverPortTextField.integerValue;
serverMutable.prefersSecuredConnection = (self.prefersSecuredConnectionCheck.state == NSControlStateValueOn);
serverMutable.serverPassword = self.serverPasswordTextField.trimmedStringValue;
server = [serverMutable copy];
if (self.serverList.count == 0) {
[self.serverListArrayController addObject:server];
} else {
[self.serverListArrayController replaceObjectAtArrangedObjectIndex:0 withObject:server];
}
}
- (void)rebuildMutableServerEndpointListIfNeeded:(id)sender
{
NSParameterAssert(sender != nil);
/* We only want to rebuild the IRCServer at index 0 when the
user changes it. This method is invoked whenever something
changes related to that server. If it was not changed while
the server endpoint sheet was open, then we must update the
mutable server list to include the change. */
if (self.serverEndpointSheet != nil) {
return;
}
[self rebuildMutableServerEndpointList:sender];
}
#pragma mark -
#pragma mark Highlight Actions
- (void)addHighlight:(id)sender
{
TDCHighlightEntrySheet *sheet =
[[TDCHighlightEntrySheet alloc] initWithConfig:nil];
sheet.delegate = self;
sheet.window = self.sheet;
[sheet startWithChannels:self.channelList];
self.highlightSheet = sheet;
}
- (void)editHighlight:(id)sender
{
NSInteger selectedRow = self.highlightsTable.selectedRow;
if (selectedRow < 0) {
return;
}
IRCHighlightMatchCondition *config = self.highlightList[selectedRow];
TDCHighlightEntrySheet *sheet =
[[TDCHighlightEntrySheet alloc] initWithConfig:config];
sheet.delegate = self;
sheet.window = self.sheet;
[sheet startWithChannels:self.channelList];
self.highlightSheet = sheet;
}
- (void)highlightEntrySheet:(TDCHighlightEntrySheet *)sender onOk:(IRCHighlightMatchCondition *)config
{
NSUInteger entryIndex =
[self.highlightList indexOfObjectPassingTest:^BOOL(id object, NSUInteger index, BOOL *stop) {
if ([[object uniqueIdentifier] isEqualToString:config.uniqueIdentifier]) {
return YES;
} else {
return NO;
}
}];
if (entryIndex == NSNotFound) {
[self.highlightListArrayController addObject:config];
} else {
[self.highlightListArrayController replaceObjectAtArrangedObjectIndex:entryIndex withObject:config];
}
}
- (void)highlightEntrySheetWillClose:(TDCHighlightEntrySheet *)sender
{
self.highlightSheet = nil;
}
- (void)deleteHighlight:(id)sender
{
NSInteger selectedRow = self.highlightsTable.selectedRow;
if (selectedRow < 0) {
return;
}
[self.highlightListArrayController removeObjectAtArrangedObjectIndex:selectedRow];
NSUInteger listCount = self.highlightList.count;
if (listCount > 0) {
if (listCount <= selectedRow) {
[self.highlightsTable selectItemAtIndex:(listCount - 1)];
} else {
[self.highlightsTable selectItemAtIndex:selectedRow];
}
}
}
#pragma mark -
#pragma mark Channel Actions
- (void)addChannel:(id)sender
{
TDCChannelPropertiesSheet *sheet =
[[TDCChannelPropertiesSheet alloc] initWithWindow:self.sheet];
sheet.delegate = self;
[sheet start];
self.channelSheet = sheet;
}
- (void)editChannel:(id)sender
{
NSInteger selectedRow = self.channelListTable.selectedRow;
if (selectedRow < 0) {
return;
}
IRCChannelConfig *config = self.channelList[selectedRow];
TDCChannelPropertiesSheet *sheet =
[[TDCChannelPropertiesSheet alloc] initWithConfig:config];
sheet.delegate = self;
sheet.window = self.sheet;
[sheet start];
self.channelSheet = sheet;
}
- (void)channelPropertiesSheet:(TDCChannelPropertiesSheet *)sender onOk:(IRCChannelConfig *)config
{
NSUInteger entryIndex =
[self.channelList indexOfObjectPassingTest:^BOOL(id object, NSUInteger index, BOOL *stop) {
if ([[object uniqueIdentifier] isEqualToString:config.uniqueIdentifier]) {
return YES;
} else {
return NO;
}
}];
[self clearChannelListPredicate];
if (entryIndex == NSNotFound) {
[self.channelListArrayController addObject:config];
} else {
[self.channelListArrayController replaceObjectAtArrangedObjectIndex:entryIndex withObject:config];
}
[self setChannelListPredicate];
}
- (void)channelPropertiesSheetWillClose:(TDCChannelPropertiesSheet *)sender
{
self.channelSheet = nil;
}
- (void)deleteChannel:(id)sender
{
NSInteger selectedRow = self.channelListTable.selectedRow;
if (selectedRow < 0) {
return;
}
[self clearChannelListPredicate];
[self.channelListArrayController removeObjectAtArrangedObjectIndex:selectedRow];
[self setChannelListPredicate];
NSUInteger listCount = self.channelList.count;
if (listCount > 0) {
if (listCount <= selectedRow) {
[self.channelListTable selectItemAtIndex:(listCount - 1)];
} else {
[self.channelListTable selectItemAtIndex:selectedRow];
}
}
}
#pragma mark -
#pragma mark Address Book Actions
- (void)showAddAddressBookEntryMenu:(id)sender
{
[self.addAddressBookEntryMenu popUpMenuPositioningItem:nil atLocation:NSMakePoint(0, 0) inView:sender];
}
- (void)addIgnoreAddressBookEntry
{
[self addIgnoreAddressBookEntryWithHostmask:nil];
}
- (void)addIgnoreAddressBookEntryWithHostmask:(nullable NSString *)hostmask
{
TDCAddressBookSheet *sheet = nil;
if (hostmask) {
IRCAddressBookEntry *config =
[IRCAddressBookEntry newIgnoreEntryForHostmask:hostmask];
sheet = [[TDCAddressBookSheet alloc] initWithConfig:config];
} else {
sheet = [[TDCAddressBookSheet alloc] initWithEntryType:IRCAddressBookEntryTypeIgnore];
}
sheet.delegate = self;
sheet.window = self.sheet;
[sheet start];
self.addressBookSheet = sheet;
}
- (void)addUserTrackingAddressBookEntry
{
TDCAddressBookSheet *sheet =
[[TDCAddressBookSheet alloc] initWithEntryType:IRCAddressBookEntryTypeUserTracking];
sheet.delegate = self;
sheet.window = self.sheet;
[sheet start];
self.addressBookSheet = sheet;
}
- (void)addAddressBookEntry:(id)sender
{
if ([sender tag] == 3) {
[self addIgnoreAddressBookEntry];
} else if ([sender tag] == 4) {
[self addUserTrackingAddressBookEntry];
}
}
- (void)editAddressBookEntryWithObject:(IRCAddressBookEntry *)entryObject
{
NSInteger tableIndex = [self.addressBookList indexOfObject:entryObject];
if (tableIndex == NSNotFound) {
return;
}
[self.addressBookTable selectItemAtIndex:tableIndex];
[self editAddressBookEntry:nil];
}
- (void)editAddressBookEntry:(id)sender
{
NSInteger selectedRow = self.addressBookTable.selectedRow;
if (selectedRow < 0) {
return;
}
IRCAddressBookEntry *config = self.addressBookList[selectedRow];
TDCAddressBookSheet *sheet =
[[TDCAddressBookSheet alloc] initWithConfig:config];
sheet.delegate = self;
sheet.window = self.sheet;
[sheet start];
self.addressBookSheet = sheet;
}
- (void)addressBookSheet:(TDCAddressBookSheet *)sender onOk:(IRCAddressBookEntry *)config
{
NSUInteger entryIndex =
[self.addressBookList indexOfObjectPassingTest:^BOOL(id object, NSUInteger index, BOOL *stop) {
if ([[object uniqueIdentifier] isEqualToString:config.uniqueIdentifier]) {
return YES;
} else {
return NO;
}
}];
if (entryIndex == NSNotFound) {
[self.addressBookArrayController addObject:config];
} else {
[self.addressBookArrayController replaceObjectAtArrangedObjectIndex:entryIndex withObject:config];
}
}
- (void)addressBookSheetWillClose:(TDCAddressBookSheet *)sender
{
self.addressBookSheet = nil;
}
- (void)deleteAddressBookEntry:(id)sender
{
NSInteger selectedRow = self.addressBookTable.selectedRow;
if (selectedRow < 0) {
return;
}
[self.addressBookArrayController removeObjectAtArrangedObjectIndex:selectedRow];
NSUInteger listCount = self.addressBookList.count;
if (listCount > 0) {
if (listCount <= selectedRow) {
[self.addressBookTable selectItemAtIndex:(listCount - 1)];
} else {
[self.addressBookTable selectItemAtIndex:selectedRow];
}
}
}
#pragma mark -
#pragma mark NSTableView Delegate
- (nullable id)tableView:(NSTableView *)tableView objectValueForTableColumn:(nullable NSTableColumn *)tableColumn row:(NSInteger)row
{
NSString *columnId = tableColumn.identifier;
if (tableView == self.channelListTable)
{
IRCChannelConfig *config = self.channelList[row];
if ([columnId isEqualToString:@"name"])
{
return config.channelName;
}
else if ([columnId isEqualToString:@"pass"])
{
NSString *secretKeyValue = config.secretKey;
if (secretKeyValue) {
return secretKeyValue;
}
return @"";
}
else if ([columnId isEqualToString:@"join"])
{
return @(config.autoJoin);
}
}
else if (tableView == self.highlightsTable)
{
IRCHighlightMatchCondition *config = self.highlightList[row];
if ([columnId isEqualToString:@"keyword"])
{
return config.matchKeyword;
}
else if ([columnId isEqualToString:@"channel"])
{
NSString *matchChannelId = config.matchChannelId;
if (matchChannelId) {
for (IRCChannelConfig *channel in self.channelList) {
if ([channel.uniqueIdentifier isEqualToString:matchChannelId] == NO) {
continue;
}
return channel.channelName;
}
}
return TXTLS(@"TDCServerPropertiesSheet[61f-6b]");
}
else if ([columnId isEqualToString:@"type"])
{
if (config.matchIsExcluded) {
return TXTLS(@"TDCServerPropertiesSheet[qcc-b4]");
} else {
return TXTLS(@"TDCServerPropertiesSheet[tet-dk]");
}
}
}
else if (tableView == self.addressBookTable)
{
IRCAddressBookEntry *config = self.addressBookList[row];
if ([columnId isEqualToString:@"hostmask"])
{
return config.hostmask;
}
else if ([columnId isEqualToString:@"type"])
{
if (config.entryType == IRCAddressBookEntryTypeIgnore) {
return TXTLS(@"TDCServerPropertiesSheet[f7o-x4]");
} else {
return TXTLS(@"TDCServerPropertiesSheet[b0g-0x]");
}
}
}
return nil;
}
- (BOOL)tableView:(NSTableView *)tableView shouldSelectRow:(NSInteger)row
{
return YES;
}
- (void)tableView:(NSTableView *)tableView setObjectValue:(nullable id)object forTableColumn:(nullable NSTableColumn *)tableColumn row:(NSInteger)row
{
NSString *columnId = tableColumn.identifier;
if (tableView == self.channelListTable)
{
IRCChannelConfigMutable *config = [self.channelList[row] mutableCopy];
if ([columnId isEqualToString:@"join"]) {
config.autoJoin = [object boolValue];
}
[self.channelListArrayController replaceObjectAtArrangedObjectIndex:row withObject:[config copy]];
}
}
- (void)tableViewSelectionDidChange:(NSNotification *)aNote
{
NSTableView *tableView = aNote.object;
if (tableView == self.channelListTable) {
[self updateChannelListPage];
} else if (tableView == self.highlightsTable) {
[self updateHighlightsPage];
} else if (tableView == self.addressBookTable) {
[self updateAddressBookPage];
}
}
- (void)tableViewDoubleClicked:(id)sender
{
if (sender == self.channelListTable) {
[self editChannel:sender];
} else if (sender == self.highlightsTable) {
[self editHighlight:sender];
} else if (sender == self.addressBookTable) {
[self editAddressBookEntry:sender];
}
}
- (BOOL)tableView:(NSTableView *)tableView writeRowsWithIndexes:(NSIndexSet *)rowIndexes toPasteboard:(NSPasteboard *)pasteboard
{
NSData *draggedData = [NSKeyedArchiver archivedDataWithRootObject:rowIndexes];
[pasteboard declareTypes:@[_tableDragToken] owner:self];
[pasteboard setData:draggedData forType:_tableDragToken];
return YES;
}
- (NSDragOperation)tableView:(NSTableView *)tableView validateDrop:(id )info proposedRow:(NSInteger)row proposedDropOperation:(NSTableViewDropOperation)dropOperation
{
return NSDragOperationGeneric;
}
- (BOOL)tableView:(NSTableView *)tableView acceptDrop:(id )info row:(NSInteger)row dropOperation:(NSTableViewDropOperation)dropOperation
{
NSPasteboard *pasteboard = [info draggingPasteboard];
NSData *draggedData = [pasteboard dataForType:_tableDragToken];
NSIndexSet *draggedRowIndexes = [NSKeyedUnarchiver unarchiveObjectWithData:draggedData];
NSUInteger draggedRowIndex = draggedRowIndexes.firstIndex;
if (tableView == self.channelListTable) {
[self clearChannelListPredicate];
[self.channelListArrayController moveObjectAtArrangedObjectIndex:draggedRowIndex toIndex:row];
[self setChannelListPredicate];
} else if (tableView == self.highlightsTable) {
[self.highlightListArrayController moveObjectAtArrangedObjectIndex:draggedRowIndex toIndex:row];
} else if (tableView == self.addressBookTable) {
[self.addressBookArrayController moveObjectAtArrangedObjectIndex:draggedRowIndex toIndex:row];
}
return YES;
}
#pragma mark -
#pragma mark NSWindow Delegate
- (void)windowWillClose:(NSNotification *)note
{
self.addressBookTable.delegate = nil;
self.channelListTable.delegate = nil;
self.highlightsTable.delegate = nil;
self.addressBookTable.dataSource = nil;
self.channelListTable.dataSource = nil;
self.highlightsTable.dataSource = nil;
[self.addressBookTable unregisterDraggedTypes];
[self.channelListTable unregisterDraggedTypes];
[self.highlightsTable unregisterDraggedTypes];
[self.sheet makeFirstResponder:nil];
if ([self.delegate respondsToSelector:@selector(serverPropertiesSheetWillClose:)]) {
[self.delegate serverPropertiesSheetWillClose:self];
}
}
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Dialogs/TDCSheetBase.m
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2008 - 2010 Satoshi Nakagawa
* Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "TVCValidatedComboBox.h"
#import "TVCValidatedTextField.h"
#import "TDCSheetBase.h"
NS_ASSUME_NONNULL_BEGIN
@implementation TDCSheetBase
- (instancetype)init
{
[self doesNotRecognizeSelector:_cmd];
return nil;
}
- (instancetype)initWithWindow:(nullable NSWindow *)window
{
if ((self = [super init])) {
self.window = window;
return self;
}
return nil;
}
- (void)startSheet
{
[self startSheetWithWindow:self.window];
}
- (void)startSheetWithWindow:(NSWindow *)window
{
[window beginSheet:self.sheet
completionHandler:^(NSModalResponse returnCode) {
[self sheetDidEndWithReturnCode:returnCode];
}];
}
- (void)endSheet
{
[self.window endSheet:self.sheet];
}
- (void)sheetDidEndWithReturnCode:(NSInteger)returnCode
{
[self.sheet close];
}
- (void)ok:(id)sender
{
[self endSheet];
}
- (BOOL)okOrErrorForTextField:(TVCValidatedTextField *)textField
{
NSParameterAssert(textField != nil);
return ([textField showValidationErrorPopover] == NO);
}
- (BOOL)okOrErrorForComboBox:(TVCValidatedComboBox *)comboBox
{
NSParameterAssert(comboBox != nil);
return ([comboBox showValidationErrorPopover] == NO);
}
- (void)cancel:(id)sender
{
[self endSheet];
}
- (void)close
{
[self cancel:nil];
}
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Dialogs/TDCWelcomeSheet.m
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2008 - 2010 Satoshi Nakagawa
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "NSStringHelper.h"
#import "IRCChannelConfig.h"
#import "IRCClientConfig.h"
#import "IRCNetworkList.h"
#import "IRCServer.h"
#import "TLOLocalization.h"
#import "TPCPreferencesLocal.h"
#import "TVCBasicTableView.h"
#import "TVCValidatedComboBox.h"
#import "TVCValidatedTextField.h"
#import "TDCWelcomeSheetPrivate.h"
NS_ASSUME_NONNULL_BEGIN
@interface TDCWelcomeSheet ()
@property (nonatomic, weak) IBOutlet NSButton *autoConnectCheck;
@property (nonatomic, weak) IBOutlet NSButton *addChannelButton;
@property (nonatomic, weak) IBOutlet NSButton *deleteChannelButton;
@property (nonatomic, weak) IBOutlet TVCValidatedTextField *nicknameTextField;
@property (nonatomic, weak) IBOutlet TVCValidatedComboBox *serverAddressComboBox;
@property (nonatomic, weak) IBOutlet TVCBasicTableView *channelTable;
@property (nonatomic, strong) NSMutableArray *channelList;
@property (nonatomic, strong) IRCNetworkList *networkList;
- (IBAction)onAddChannel:(id)sender;
- (IBAction)onDeleteChannel:(id)sender;
@end
@implementation TDCWelcomeSheet
#pragma mark -
#pragma mark Init.
- (instancetype)initWithWindow:(nullable NSWindow *)window
{
if ((self = [super initWithWindow:window])) {
[self prepareInitialState];
return self;
}
return nil;
}
- (void)prepareInitialState
{
[RZMainBundle() loadNibNamed:@"TDCWelcomeSheet" owner:self topLevelObjects:nil];
/* Populate server list combo box */
self.networkList = [IRCNetworkList new];
NSArray *listOfNetworks = self.networkList.listOfNetworks;
for (IRCNetwork *network in listOfNetworks) {
[self.serverAddressComboBox addItemWithObjectValue:network.networkName];
}
/* Nickname */
self.nicknameTextField.textDidChangeCallback = self;
self.nicknameTextField.stringValueIsInvalidOnEmpty = YES;
self.nicknameTextField.stringValueIsTrimmed = YES;
self.nicknameTextField.stringValueUsesOnlyFirstToken = YES;
self.nicknameTextField.validationBlock = ^NSString *(NSString *currentValue) {
if (currentValue.isHostmaskNickname == NO) {
return TXTLS(@"CommonErrors[och-j5]");
}
return nil;
};
/* Server address */
self.serverAddressComboBox.textDidChangeCallback = self;
self.serverAddressComboBox.stringValueIsInvalidOnEmpty = YES;
self.serverAddressComboBox.stringValueIsTrimmed = YES;
self.serverAddressComboBox.stringValueUsesOnlyFirstToken = YES;
self.serverAddressComboBox.validationBlock = ^NSString *(NSString *currentValue) {
if (currentValue.isValidInternetAddress == NO) {
return TXTLS(@"CommonErrors[yyx-l3]");
}
return nil;
};
/* Setup others */
self.channelList = [NSMutableArray new];
self.channelTable.textEditingDelegate = self;
[self updateDeleteChannelButton];
self.nicknameTextField.stringValue = [TPCPreferences defaultNickname];
}
#pragma mark -
#pragma mark Controls
- (void)start
{
[self startSheet];
}
- (void)close
{
[super cancel:nil];
}
- (void)ok:(id)sender
{
if ([self okOrError] == NO) {
return;
}
IRCClientConfigMutable *config = nil;
NSString *serverAddress = self.serverAddressComboBox.value;
IRCNetwork *serverAddressNetwork = [self.networkList networkNamed:serverAddress];
if (serverAddressNetwork == nil) {
serverAddressNetwork = [self.networkList networkWithServerAddress:serverAddress];
}
if (serverAddressNetwork) {
config = [IRCClientConfigMutable newConfigWithNetwork:serverAddressNetwork];
} else {
serverAddress = serverAddress.lowercaseString;
config = [IRCClientConfigMutable new];
config.connectionName = serverAddress;
IRCServerMutable *server = [IRCServerMutable new];
server.serverAddress = serverAddress;
config.serverList = @[[server copy]];
}
config.autoConnect = (self.autoConnectCheck.state == NSControlStateValueOn);
config.nickname = self.nicknameTextField.value;
NSMutableArray *channelList = [NSMutableArray array];
NSMutableArray *channelsAdded = [NSMutableArray array];
for (NSString *channel in self.channelList) {
NSString *channelName = channel.trim;
if (channelName.length == 0) {
continue;
}
if ([channelsAdded containsObjectIgnoringCase:channelName] == NO) {
[channelsAdded addObject:channelName];
} else {
continue;
}
if (channelName.isChannelName == NO) {
channelName = [@"#" stringByAppendingString:channelName];
}
IRCChannelConfig *channelConfig = [IRCChannelConfig seedWithName:channelName];
[channelList addObject:channelConfig];
}
config.channelList = channelList;
if ([self.delegate respondsToSelector:@selector(welcomeSheet:onOk:)]) {
[self.delegate welcomeSheet:self onOk:[config copy]];
}
[super ok:nil];
}
- (BOOL)okOrError
{
if ([self okOrErrorForComboBox:self.serverAddressComboBox] == NO) {
return NO;
}
if ([self okOrErrorForTextField:self.nicknameTextField] == NO) {
return NO;
}
return YES;
}
- (void)onAddChannel:(id)sender
{
[self.channelList addObject:@""];
[self.channelTable reloadData];
NSInteger rowToEdit = (self.channelList.count - 1);
[self.channelTable selectItemAtIndex:rowToEdit];
[self.channelTable editColumn:0 row:rowToEdit withEvent:nil select:YES];
}
- (void)onDeleteChannel:(id)sender
{
NSInteger selectedRow = self.channelTable.selectedRow;
if (selectedRow < 0) {
return;
}
[self.channelList removeObjectAtIndex:selectedRow];
[self.channelTable reloadData];
NSInteger channelListCount = self.channelList.count;
if (selectedRow > channelListCount) {
selectedRow = (channelListCount - 1);
}
if (channelListCount >= 0) {
[self.channelTable selectItemAtIndex:selectedRow];
}
[self updateDeleteChannelButton];
}
- (void)updateDeleteChannelButton
{
self.deleteChannelButton.enabled = (self.channelTable.numberOfSelectedRows > 0);
}
#pragma mark -
#pragma mark NSTableView Delegate
- (void)textDidEndEditing:(NSNotification *)note
{
NSInteger editedRow = self.channelTable.editedRow;
if (editedRow < 0) {
return;
}
NSString *editedString = [note.object textStorage].string;
self.channelList[editedRow] = [editedString copy];
[self.channelTable reloadData];
[self.channelTable selectItemAtIndex:editedRow];
[self updateDeleteChannelButton];
}
- (NSInteger)numberOfRowsInTableView:(NSTableView *)sender
{
return self.channelList.count;
}
- (id)tableView:(NSTableView *)sender objectValueForTableColumn:(NSTableColumn *)column row:(NSInteger)row
{
return self.channelList[row];
}
- (void)tableViewSelectionIsChanging:(NSNotification *)note
{
[self updateDeleteChannelButton];
}
#pragma mark -
#pragma mark NSWindow Delegate
- (void)windowWillClose:(NSNotification *)note
{
self.channelTable.dataSource = nil;
self.channelTable.delegate = nil;
if ([self.delegate respondsToSelector:@selector(welcomeSheetWillClose:)]) {
[self.delegate welcomeSheetWillClose:self];
}
}
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Dialogs/TDCWindowBase.m
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "TDCWindowBase.h"
NS_ASSUME_NONNULL_BEGIN
@implementation TDCWindowBase
- (void)show
{
[self.window makeKeyAndOrderFront:nil];
}
- (void)close
{
[self.window close];
}
- (void)ok:(id)sender
{
[self close];
}
- (void)cancel:(id)sender
{
[self close];
}
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/External Libraries/GTMEncodeHTML.h
================================================
//
// GTMNSString+HTML.h
// Dealing with NSStrings that contain HTML
//
// Copyright 2006-2008 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy
// of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.
//
#import
NS_ASSUME_NONNULL_BEGIN
/// Utilities for NSStrings containing HTML
@interface NSString (GTMNSStringHTMLAdditions)
/// Get a string where internal characters that need escaping for HTML are escaped
///
/// For example, '&' become '&'. This will only cover characters from table
/// A.2.2 of http://www.w3.org/TR/xhtml1/dtds.html#a_dtd_Special_characters
/// which is what you want for a unicode encoded webpage. If you have a ascii
/// or non-encoded webpage, please use stringByEscapingAsciiHTML which will
/// encode all characters.
///
/// For obvious reasons this call is only safe once.
///
/// Returns:
/// Autoreleased NSString
///
@property (readonly, copy, nullable) NSString *gtm_stringByEscapingForHTML;
/// Get a string where internal characters that need escaping for HTML are escaped
///
/// For example, '&' become '&'
/// All non-mapped characters (unicode that don't have a &keyword; mapping)
/// will be converted to the appropriate xx; value. If your webpage is
/// unicode encoded (UTF16 or UTF8) use stringByEscapingHTML instead as it is
/// faster, and produces less bloated and more readable HTML (as long as you
/// are using a unicode compliant HTML reader).
///
/// For obvious reasons this call is only safe once.
///
/// Returns:
/// Autoreleased NSString
///
@property (readonly, copy) NSString *gtm_stringByEscapingForAsciiHTML;
/// Get a string where internal characters that are escaped for HTML are unescaped
///
/// For example, '&' becomes '&'
/// Handles and 2 cases as well
///
/// Returns:
/// Autoreleased NSString
///
@property (readonly, copy) NSString *gtm_stringByUnescapingFromHTML;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/External Libraries/OELReachability.h
================================================
/*
Copyright (c) 2011, Tony Million.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#import
NS_ASSUME_NONNULL_BEGIN
@class OELReachability;
typedef void (^OELReachabilityNetworkReachableBlock)(OELReachability *reachability);
typedef void (^OELReachabilityNetworkUnreachableBlock)(OELReachability *reachability);
@interface OELReachability : NSObject
@property (nonatomic, copy, nullable) OELReachabilityNetworkReachableBlock reachableBlock;
@property (nonatomic, copy, nullable) OELReachabilityNetworkUnreachableBlock unreachableBlock;
+ (nullable OELReachability *)reachabilityForInternetConnection;
@property (getter=isReachable, readonly) BOOL reachable;
- (BOOL)startNotifier;
- (void)stopNotifier;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/IRC.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
/* Hard limits */
#define TXMaximumIRCBodyLength 510
#define TXMaximumIRCNicknameLength 50
#define TXMaximumIRCUsernameLength 40
#define TXMaximumTCPPort 65535
#define TXMaximumNodesPerModeCommand 4
#define IRCProtocolDefaultNicknameMaximumLength 31
================================================
FILE: Sources/App/Classes/Headers/IRCAddressBook.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
NS_ASSUME_NONNULL_BEGIN
typedef NS_ENUM(NSUInteger, IRCAddressBookEntryType) {
IRCAddressBookEntryTypeIgnore = 0,
IRCAddressBookEntryTypeUserTracking,
/* Entry type used when multiple instances of IRCAddressBookEntry
are combined into a single object which represents all. */
IRCAddressBookEntryTypeMixed
};
typedef NS_ENUM(NSUInteger, IRCAddressBookUserTrackingStatus) {
IRCAddressBookUserTrackingStatusUnknown = 0,
IRCAddressBookUserTrackingStatusSignedOff,
IRCAddressBookUserTrackingStatusSignedOn,
IRCAddressBookUserTrackingStatusAvailable,
IRCAddressBookUserTrackingStatusNotAvailable,
IRCAddressBookUserTrackingStatusAway,
IRCAddressBookUserTrackingStatusNotAway
};
#pragma mark -
#pragma mark Immutable Object
@interface IRCAddressBookEntry : XRPortablePropertyDict
@property (readonly) IRCAddressBookEntryType entryType;
@property (readonly, copy) NSString *uniqueIdentifier;
@property (readonly, copy) NSString *hostmask;
@property (readonly, copy) NSString *hostmaskRegularExpression;
@property (readonly, copy, nullable) NSString *trackingNickname;
@property (readonly) BOOL ignoreClientToClientProtocol;
@property (readonly) BOOL ignoreGeneralEventMessages;
@property (readonly) BOOL ignoreNoticeMessages;
@property (readonly) BOOL ignorePrivateMessageHighlights;
@property (readonly) BOOL ignorePrivateMessages;
@property (readonly) BOOL ignorePublicMessageHighlights;
@property (readonly) BOOL ignorePublicMessages;
@property (readonly) BOOL ignoreFileTransferRequests;
@property (readonly) BOOL ignoreInlineMedia;
@property (readonly) BOOL ignoreMessagesContainingMatch;
@property (readonly) BOOL trackUserActivity;
/* When IRCAddressBookEntryTypeMixed is mixed, this array holds
a reference to each entry that is mixed into the current object. */
@property (readonly, copy, nullable) NSArray *parentEntries;
+ (instancetype)newIgnoreEntry;
+ (instancetype)newIgnoreEntryForHostmask:(nullable NSString *)hostmask;
+ (instancetype)newUserTrackingEntry;
- (BOOL)checkMatch:(NSString *)hostmask;
@end
#pragma mark -
#pragma mark Mutable Object
@interface IRCAddressBookEntryMutable : IRCAddressBookEntry
@property (nonatomic, assign, readwrite) IRCAddressBookEntryType entryType;
@property (nonatomic, copy, readwrite) NSString *hostmask;
@property (nonatomic, assign, readwrite) BOOL ignoreClientToClientProtocol;
@property (nonatomic, assign, readwrite) BOOL ignoreGeneralEventMessages;
@property (nonatomic, assign, readwrite) BOOL ignoreNoticeMessages;
@property (nonatomic, assign, readwrite) BOOL ignorePrivateMessageHighlights;
@property (nonatomic, assign, readwrite) BOOL ignorePrivateMessages;
@property (nonatomic, assign, readwrite) BOOL ignorePublicMessageHighlights;
@property (nonatomic, assign, readwrite) BOOL ignorePublicMessages;
@property (nonatomic, assign, readwrite) BOOL ignoreFileTransferRequests;
@property (nonatomic, assign, readwrite) BOOL ignoreInlineMedia;
@property (nonatomic, assign, readwrite) BOOL trackUserActivity;
@property (nonatomic, copy, readwrite, nullable) NSArray *parentEntries;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/IRCAddressBookUserTracking.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "IRCAddressBook.h"
NS_ASSUME_NONNULL_BEGIN
@class IRCClient;
TEXTUAL_EXTERN NSNotificationName const IRCAddressBookUserTrackingStatusChangedNotification;
TEXTUAL_EXTERN NSNotificationName const IRCAddressBookUserTrackingAddedTrackedUserNotification;
TEXTUAL_EXTERN NSNotificationName const IRCAddressBookUserTrackingRemovedTrackedUserNotification;
TEXTUAL_EXTERN NSNotificationName const IRCAddressBookUserTrackingRemovedAllTrackedUsersNotification;
@interface IRCAddressBookUserTrackingContainer : NSObject
@property (readonly, weak) IRCClient *client;
// value is boolean, whether tracked user is online
@property (readonly, copy) NSDictionary *trackedUsers;
- (IRCAddressBookUserTrackingStatus)statusOfUser:(NSString *)nickname;
- (IRCAddressBookUserTrackingStatus)statusOfEntry:(IRCAddressBookEntry *)addressBookEntry;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/IRCChannel.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2008 - 2010 Satoshi Nakagawa
* Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "IRCChannelConfig.h"
#import "IRCChannelMemberList.h"
#import "IRCTreeItem.h"
NS_ASSUME_NONNULL_BEGIN
@class IRCChannelMode, IRCChannelUser, IRCUser;
@class TVCLogLine;
typedef NS_ENUM(NSUInteger, IRCChannelStatus) {
IRCChannelStatusParted = 0,
IRCChannelStatusJoining,
IRCChannelStatusJoined,
IRCChannelStatusTerminated,
};
TEXTUAL_EXTERN NSNotificationName const IRCChannelConfigurationWasUpdatedNotification;
@interface IRCChannel : IRCTreeItem
@property (readonly, copy) IRCChannelConfig *config;
@property (nonatomic, copy) NSString *name; // -setName: will do nothing if type != IRCChannelTypePrivateMessage
@property (nonatomic, copy, nullable) NSString *topic;
@property (nonatomic, assign) BOOL autoJoin;
@property (readonly) IRCChannelType type;
@property (getter=isChannel, readonly) BOOL channel;
@property (getter=isPrivateMessage, readonly) BOOL privateMessage;
@property (getter=isPrivateMessageForZNCUser, readonly) BOOL privateMessageForZNCUser; // For example: *status, *nickserv, etc.
@property (getter=isUtility, readonly) BOOL utility; // See IRCChannelTypeUtility in IRCChannelConfig.h
@property (readonly) IRCChannelStatus status;
@property (readonly) BOOL errorOnLastJoinAttempt;
@property (readonly) NSTimeInterval channelJoinTime;
@property (readonly, copy) NSString *channelTypeString;
@property (readonly, strong, nullable) IRCChannelMode *modeInfo;
@property (readonly, strong, nullable) IRCChannelMemberList *memberInfo;
@property (readonly, copy, nullable) NSString *secretKey;
@property (readonly, copy, nullable) NSURL *logFilePath;
@property (readonly) NSUInteger logFileSessionCount; // Number of lines sent to channel log file for session (from connect to disconnect)
@property (readonly, weak) TVCLogLine *lastLine; // Last line in the channel. There is no guarantee it's visible to the user when accessed.
#if TEXTUAL_BUILT_WITH_ADVANCED_ENCRYPTION == 1
@property (readonly) BOOL encryptionStateIsEncrypted;
#endif
- (instancetype)init NS_UNAVAILABLE;
- (void)activate;
- (void)deactivate;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/IRCChannelConfig.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2008 - 2010 Satoshi Nakagawa
* Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "TLONotificationController.h"
NS_ASSUME_NONNULL_BEGIN
typedef NS_ENUM(NSUInteger, IRCChannelType) {
IRCChannelTypeChannel = 0,
IRCChannelTypePrivateMessage,
IRCChannelTypeUtility,
};
#pragma mark -
#pragma mark Immutable Object
@interface IRCChannelConfig : XRPortablePropertyDict
@property (readonly) BOOL autoJoin;
@property (readonly) BOOL ignoreGeneralEventMessages;
@property (readonly) BOOL ignoreHighlights;
@property (readonly) BOOL inlineMediaDisabled;
@property (readonly) BOOL inlineMediaEnabled;
@property (readonly) BOOL pushNotifications;
@property (readonly) BOOL showTreeBadgeCount;
@property (readonly) IRCChannelType type;
@property (readonly, copy) NSString *channelName;
@property (readonly, copy) NSString *uniqueIdentifier;
@property (readonly, copy, nullable) NSString *label;
@property (readonly, copy, nullable) NSString *defaultModes;
@property (readonly, copy, nullable) NSString *defaultTopic;
@property (readonly, copy, nullable) NSString *secretKey;
@property (readonly, copy, nullable) NSString *secretKeyFromKeychain;
+ (IRCChannelConfig *)seedWithName:(NSString *)channelName;
/* Notifications */
- (nullable NSString *)soundForEvent:(TXNotificationType)event;
// These methods return an integer because there are more than
// two possible values. When there is no channel defined value
// for the given event, NSControlStateValueMixed is returned
// which indicates that the global value should be used.
// NSControlStateValueOn and NSControlStateValueOff
// are returned when a channel defined value is available.
- (NSControlStateValue)notificationEnabledForEvent:(TXNotificationType)event;
- (NSControlStateValue)disabledWhileAwayForEvent:(TXNotificationType)event;
- (NSControlStateValue)bounceDockIconForEvent:(TXNotificationType)event;
- (NSControlStateValue)bounceDockIconRepeatedlyForEvent:(TXNotificationType)event;
- (NSControlStateValue)speakEvent:(TXNotificationType)event;
@end
#pragma mark -
#pragma mark Mutable Object
@interface IRCChannelConfigMutable : IRCChannelConfig
@property (nonatomic, assign, readwrite) IRCChannelType type;
@property (nonatomic, assign, readwrite) BOOL autoJoin;
@property (nonatomic, assign, readwrite) BOOL ignoreGeneralEventMessages;
@property (nonatomic, assign, readwrite) BOOL ignoreHighlights;
@property (nonatomic, assign, readwrite) BOOL inlineMediaDisabled;
@property (nonatomic, assign, readwrite) BOOL inlineMediaEnabled;
@property (nonatomic, assign, readwrite) BOOL pushNotifications;
@property (nonatomic, assign, readwrite) BOOL showTreeBadgeCount;
@property (nonatomic, copy, readwrite) NSString *channelName;
@property (nonatomic, copy, readwrite, nullable) NSString *label;
@property (nonatomic, copy, readwrite, nullable) NSString *defaultModes;
@property (nonatomic, copy, readwrite, nullable) NSString *defaultTopic;
@property (nonatomic, copy, readwrite, nullable) NSString *secretKey;
- (void)setSound:(nullable NSString *)value forEvent:(TXNotificationType)event;
// NSControlStateValueOn = YES
// NSControlStateValueOff = NO
// NSControlStateValueMixed = Reset, use default
- (void)setNotificationEnabled:(NSControlStateValue)value forEvent:(TXNotificationType)event;
- (void)setDisabledWhileAway:(NSControlStateValue)value forEvent:(TXNotificationType)event;
- (void)setBounceDockIcon:(NSControlStateValue)value forEvent:(TXNotificationType)event;
- (void)setBounceDockIconRepeatedly:(NSControlStateValue)value forEvent:(TXNotificationType)event;
- (void)setEventIsSpoken:(NSControlStateValue)value forEvent:(TXNotificationType)event;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/IRCChannelMemberList.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
NS_ASSUME_NONNULL_BEGIN
@class IRCChannelUser, IRCUser;
#pragma mark -
#pragma mark Prototype
/* IRCChannel proxies many methods declared by IRCChannelMemberList
for backwards compatibility and convenience through the use of
IRCChannelMemberListPrototype protocol. It's atypical to access
IRCChannelMemberList directly. The declaration for it is only
public to allow KVO binding to -memberList and -numberOfMembers. */
/* In context of IRCChannel proxied methods:
An instance of IRCChannel will only have a member list when in
active state. This includes regular channels and private messages.
Utility channels will never have a member list.
All proxied methods will do nothing when there is no member list.
*/
@protocol IRCChannelMemberListPrototype
/* Member changes (adding, removing, modifying) are done so asynchronously.
This means that changes wont be immediately reflected by -memberList. */
/* It is safe to call -memberExists: and -findMember: immediately after
changing a member because those methods do not require the member to
be present in the member list to produce a result. */
- (void)addUser:(IRCUser *)user;
- (void)addMember:(IRCChannelUser *)member;
- (void)removeMember:(IRCChannelUser *)member;
- (void)removeMemberWithNickname:(NSString *)nickname;
- (BOOL)memberExists:(NSString *)nickname;
- (nullable IRCChannelUser *)findMember:(NSString *)nickname;
/* -memberList and -numberOfMembers are KVO compliant when
bound directly to an instance of IRCChannelMemberList.
The methods that IRCChannel proxy will not post KVO changes. */
@property (readonly) NSUInteger numberOfMembers;
@property (readonly, copy, nullable) NSArray *memberList; // Automatically sorted by channel rank
/* Resort the entire member list using all known conditions. */
/* This can be an expensive task for large channels. */
- (void)sortMembers;
@end
#pragma mark -
#pragma mark Interface
@interface IRCChannelMemberList : NSObject
- (instancetype)init NS_UNAVAILABLE;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/IRCChannelMode.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2008 - 2010 Satoshi Nakagawa
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
NS_ASSUME_NONNULL_BEGIN
@class IRCChannelModeContainer, IRCModeInfo;
@interface IRCChannelMode : NSObject
- (BOOL)modeIsDefined:(NSString *)modeSymbol;
- (nullable IRCModeInfo *)modeInfoFor:(NSString *)modeSymbol;
@property (readonly, copy) IRCChannelModeContainer *modes;
@property (readonly, copy) NSString *string;
@property (readonly, copy) NSString *stringWithMaskedPassword;
- (NSString *)getChangeCommand:(IRCChannelModeContainer *)modes;
- (instancetype)init NS_UNAVAILABLE;
@end
#pragma mark -
@interface IRCChannelModeContainer : NSObject
@property (readonly, copy) NSDictionary *modes;
- (BOOL)modeIsDefined:(NSString *)modeSymbol;
- (nullable IRCModeInfo *)modeInfoFor:(NSString *)modeSymbol;
- (void)changeMode:(NSString *)modeSymbol modeIsSet:(BOOL)modeIsSet;
- (void)changeMode:(NSString *)modeSymbol modeIsSet:(BOOL)modeIsSet modeParameter:(nullable NSString *)modeParameter;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/IRCChannelUser.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2008 - 2010 Satoshi Nakagawa
* Copyright (c) 2010 - 2019 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
NS_ASSUME_NONNULL_BEGIN
@class IRCUser, IRCUserMutable;
typedef NS_OPTIONS(NSUInteger, IRCUserRank) {
IRCUserRankNone = 1 << 0, // nothing
IRCUserRankIRCopByMode = 1 << 1, // +y/+Y
IRCUserRankChannelOwner = 1 << 2, // +q
IRCUserRankSuperOperator = 1 << 3, // +a
IRCUserRankNormalOperator = 1 << 4, // +o
IRCUserRankHalfOperator = 1 << 5, // +h
IRCUserRankVoiced = 1 << 6 // +v
};
#pragma mark -
#pragma mark Immutable Object
@interface IRCChannelUser : XRPortablePropertyObject
@property (readonly, strong) IRCUser *user;
@property (getter=isOp, readonly) BOOL op;
@property (getter=isHalfOp, readonly) BOOL halfOp;
// -rank(s) returns IRCUserRankIRCopByMode if the +Y/+y modes defined
// by InspIRCd-2.0 for IRC operators are in use by this user. It does not
// return this if the user is an IRC operator, but lacks these modes.
// Use -isCop for the status of the user regardless of these modes.
@property (readonly) IRCUserRank rank; // Highest rank user has
@property (readonly) IRCUserRank ranks; // All ranks user as a bitmask
@property (readonly, copy) NSString *modes; // List of all user modes, ranked highest to lowest
@property (readonly, copy) NSString *mark; // Returns mode symbol for highest rank (-modes)
/* Weight used when completing nicknames. */
/* Accessing totalWeight decays the weight. */
/* Accessing other weight properties does not. */
@property (readonly) double totalWeight; // (incoming + outgoing) with decay
@property (readonly) double incomingWeight;
@property (readonly) double outgoingWeight;
/* Timestamp instance of IRCChannelUser was created. */
@property (readonly) NSTimeInterval creationTime;
- (instancetype)init NS_UNAVAILABLE;
@end
#pragma mark -
#pragma mark Mutable Object
@interface IRCChannelUserMutable : IRCChannelUser
@property (nonatomic, copy, readwrite) NSString *modes;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/IRCClient.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2008 - 2010 Satoshi Nakagawa
* Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "IRCCommandIndex.h"
#import "IRCConnection.h"
#import "IRCTreeItem.h"
#import "TLOEncryptionManager.h"
#import "TVCLogController.h"
#import "TVCLogLine.h"
NS_ASSUME_NONNULL_BEGIN
@class IRCChannel, IRCClientConfig, IRCHighlightLogEntry, IRCISupportInfo;
@class IRCAddressBookEntry, IRCMessage, IRCServer, IRCUser;
typedef NS_ENUM(NSUInteger, IRCClientConnectMode) {
IRCClientConnectModeNormal = 0,
IRCClientConnectModeRetry,
IRCClientConnectModeReconnect,
};
typedef NS_ENUM(NSUInteger, IRCClientDisconnectMode) {
IRCClientDisconnectModeNormal = 0,
IRCClientDisconnectModeComputerSleep,
IRCClientDisconnectModeBadCertificate,
IRCClientDisconnectModeReachabilityChange,
IRCClientDisconnectModeServerRedirect
};
typedef NS_OPTIONS(NSUInteger, ClientIRCv3SupportedCapability) {
ClientIRCv3SupportedCapabilityAwayNotify = 1 << 0, // YES if away-notify CAP supported
ClientIRCv3SupportedCapabilityBatch = 1 << 1, // YES if batch CAP supported
ClientIRCv3SupportedCapabilityEchoMessage = 1 << 2, // YES if echo-message CAP supported
ClientIRCv3SupportedCapabilityIdentifyCTCP = 1 << 3, // YES if identify-ctcp CAP supported
ClientIRCv3SupportedCapabilityIdentifyMsg = 1 << 4, // YES if identify-msg CAP supported
ClientIRCv3SupportedCapabilityIsIdentifiedWithSASL = 1 << 5, // YES if SASL authentication was successful
ClientIRCv3SupportedCapabilityIsInSASLNegotiation = 1 << 6, // YES if in SASL CAP authentication request
ClientIRCv3SupportedCapabilityMonitorCommand = 1 << 7, // YES if the MONITOR command is supported
ClientIRCv3SupportedCapabilityMultiPrefix = 1 << 8, // YES if multi-prefix CAP supported
ClientIRCv3SupportedCapabilityPlayback = 1 << 9, // Special CAP which is subject to change
ClientIRCv3SupportedCapabilityServerTime = 1 << 10, // YES if server-time CAP supported
ClientIRCv3SupportedCapabilityUserhostInNames = 1 << 11, // YES if userhost-in-names CAP supported
ClientIRCv3SupportedCapabilityWatchCommand = 1 << 12, // YES if the WATCH command is supported
ClientIRCv3SupportedCapabilityZNCCertInfoModule = 1 << 13, // YES if the ZNC vendor specific CAP supported
ClientIRCv3SupportedCapabilityZNCSelfMessage = 1 << 14, // YES if the ZNC vendor specific CAP supported
ClientIRCv3SupportedCapabilityChangeHost = 1 << 15 // YES if the CHGHOST CAP supported
};
TEXTUAL_EXTERN NSNotificationName const IRCClientConfigurationWasUpdatedNotification;
TEXTUAL_EXTERN NSNotificationName const IRCClientChannelListWasModifiedNotification;
TEXTUAL_EXTERN NSNotificationName const IRCClientWillConnectNotification;
TEXTUAL_EXTERN NSNotificationName const IRCClientDidConnectNotification;
TEXTUAL_EXTERN NSNotificationName const IRCClientWillSendQuitNotification;
TEXTUAL_EXTERN NSNotificationName const IRCClientWillDisconnectNotification;
TEXTUAL_EXTERN NSNotificationName const IRCClientDidDisconnectNotification;
TEXTUAL_EXTERN NSNotificationName const IRCClientUserNicknameChangedNotification;
@interface IRCClient : IRCTreeItem
@property (readonly, copy) IRCClientConfig *config;
@property (readonly, copy, nullable) IRCServer *server; // Where is being connected to. Use -serverAddress for server address connected to.
@property (readonly) IRCISupportInfo *supportInfo;
@property (readonly) IRCClientConnectMode connectType;
@property (readonly) IRCClientDisconnectMode disconnectType;
@property (readonly) BOOL isAutojoined; // YES if autojoin has completed
@property (readonly) BOOL isAutojoining; // YES if autojoin is in progress
@property (readonly) BOOL isConnecting; // YES if socket is connecting. Set to NO on raw numeric 001.
@property (readonly) BOOL isConnected; // YES if socket is connected
@property (readonly) BOOL isConnectedToZNC; // YES if Textual detected that this connection is ZNC
@property (readonly) BOOL isLoggedIn; // YES if logged into server. Set to YES on raw numeric 001.
@property (readonly) BOOL isQuitting; // YES if socket is disconnecting
@property (readonly) BOOL isReconnecting; // YES if reconnect is pending
@property (readonly) BOOL isSecured; // YES if socket is connected using SSL/TLS
@property (readonly) BOOL userIsAway; // YES if local user is away
@property (readonly) BOOL userIsIRCop; // YES if local user is IRCop
@property (readonly) BOOL userIsIdentifiedWithNickServ; // YES if NickServ identification was successful
@property (readonly) BOOL isWaitingForNickServ; // YES if NickServ identification is pending
@property (readonly) BOOL serverHasNickServ; // YES if NickServ service was found on server
@property (readonly) NSTimeInterval lastMessageReceived; // The time at which the last of any incoming data was received
@property (readonly) NSTimeInterval lastMessageServerTime; // The time of the last message received that contained a server-time CAP
@property (readonly) NSUInteger channelCount;
@property (readonly, weak) IRCChannel *lastSelectedChannel; // If this is the selected client, then the value of this property is the current selection. If the current client is not selected, then this value is either its previous selection or nil.
@property (readonly, weak) TVCLogLine *lastLine; // Last line in the server console. There is no guarantee it's visible to the user when accessed.
@property (readonly, copy) NSArray *channelList;
@property (readonly, copy) NSArray *cachedHighlights;
@property (readonly, copy, nullable) NSString *userHostmask; // The hostmask of the local user
@property (readonly, copy) NSString *userNickname; // The nickname of the local user
@property (readonly, copy, nullable) NSString *serverAddress; // The address of the server connected to or nil
@property (readonly, copy, nullable) NSString *networkName; // The name of the network connected to or nil
@property (readonly, copy) NSString *networkNameAlt; // The name of the network connected to or the configured Connection Name
@property (readonly, copy, nullable) NSString *preAwayUserNickname; // Nickname before away was set or nil
@property (readonly, copy, nullable) NSData *zncBouncerCertificateChainData;
@property (readonly) NSUInteger logFileSessionCount; // Number of lines sent to server console log file for session (from connect to disconnect)
- (instancetype)init NS_UNAVAILABLE;
- (void)connect;
- (void)connect:(IRCClientConnectMode)connectMode;
- (void)connect:(IRCClientConnectMode)connectMode bypassProxy:(BOOL)bypassProxy;
- (void)quit;
- (void)quitWithComment:(NSString *)comment;
- (void)cancelReconnect;
@property (readonly) ClientIRCv3SupportedCapability capacities;
@property (readonly, copy) NSString *enabledCapacitiesStringValue;
- (BOOL)isCapabilitySupported:(NSString *)capabilityString;
- (BOOL)isCapabilityEnabled:(ClientIRCv3SupportedCapability)capability;
- (void)joinChannel:(IRCChannel *)channel;
- (void)joinChannel:(IRCChannel *)channel password:(nullable NSString *)password;
- (void)joinChannels:(NSArray *)channels;
- (void)joinUnlistedChannel:(NSString *)channel;
- (void)joinUnlistedChannel:(NSString *)channel password:(nullable NSString *)password;
- (void)forceJoinChannel:(NSString *)channel password:(nullable NSString *)password;
- (void)partChannel:(IRCChannel *)channel;
- (void)partChannel:(IRCChannel *)channel withComment:(nullable NSString *)comment;
- (void)partUnlistedChannel:(NSString *)channel;
- (void)partUnlistedChannel:(NSString *)channel withComment:(nullable NSString *)comment;
- (void)changeNickname:(NSString *)newNickname;
- (void)kick:(NSString *)nickname inChannel:(IRCChannel *)channel;
- (void)sendCTCPQuery:(NSString *)nickname command:(NSString *)command text:(nullable NSString *)text;
- (void)sendCTCPReply:(NSString *)nickname command:(NSString *)command text:(nullable NSString *)text;
- (void)sendCTCPPing:(NSString *)nickname;
- (void)sendWhois:(NSString *)nickname;
- (void)sendWhoToChannel:(IRCChannel *)channel;
- (void)sendWhoToChannelNamed:(NSString *)channel;
- (void)toggleAwayStatus:(BOOL)setAway;
- (void)toggleAwayStatus:(BOOL)setAway withComment:(nullable NSString *)comment;
- (void)requestModesForChannel:(IRCChannel *)channel;
- (void)requestModesForChannelNamed:(NSString *)channel;
- (void)sendModes:(nullable NSString *)modeSymbols withParameters:(nullable NSArray *)parameters inChannel:(IRCChannel *)channel;
- (void)sendModes:(nullable NSString *)modeSymbols withParametersString:(nullable NSString *)parametersString inChannel:(IRCChannel *)channel;
- (void)sendModes:(nullable NSString *)modeSymbols withParameters:(nullable NSArray *)parameters inChannelNamed:(NSString *)channel;
- (void)sendModes:(nullable NSString *)modeSymbols withParametersString:(nullable NSString *)parametersString inChannelNamed:(NSString *)channel;
- (void)sendPing:(NSString *)tokenString;
- (void)sendPong:(NSString *)tokenString;
- (void)sendInviteTo:(NSString *)nickname toJoinChannel:(IRCChannel *)channel;
- (void)sendInviteTo:(NSString *)nickname toJoinChannelNamed:(NSString *)channel;
- (void)requestTopicForChannel:(IRCChannel *)channel;
- (void)requestTopicForChannelNamed:(NSString *)channel;
- (void)sendTopicTo:(nullable NSString *)topic inChannel:(IRCChannel *)channel;
- (void)sendTopicTo:(nullable NSString *)topic inChannelNamed:(NSString *)channel;
- (void)sendCapability:(NSString *)subcommand data:(nullable NSString *)data;
- (void)sendIsonForNicknames:(NSArray *)nicknames;
- (void)modifyWatchListBy:(BOOL)adding nicknames:(NSArray *)nicknames;
- (void)requestChannelList;
- (NSArray *)compileListOfModeChangesForModeSymbol:(NSString *)modeSymbol modeIsSet:(BOOL)modeIsSet parameterString:(NSString *)parameterString;
- (NSArray *)compileListOfModeChangesForModeSymbol:(NSString *)modeSymbol modeIsSet:(BOOL)modeIsSet parameterString:(NSString *)parameterString characterSet:(NSCharacterSet *)characterList;
- (NSArray *)compileListOfModeChangesForModeSymbol:(NSString *)modeSymbol modeIsSet:(BOOL)modeIsSet modeParameters:(NSArray *)modeParameters;
- (void)createChannelListDialog;
- (void)createChannelInviteExceptionListSheet;
- (void)createChannelBanExceptionListSheet;
- (void)createChannelBanListSheet;
- (void)createChannelQuietListSheet;
- (void)presentCertificateTrustInformation;
- (void)closeDialogs;
#pragma mark -
- (BOOL)userExists:(NSString *)nickname;
- (nullable IRCUser *)findUser:(NSString *)nickname;
- (IRCUser *)findUserOrCreate:(NSString *)nickname;
@property (readonly) NSUInteger numberOfUsers;
@property (readonly, copy) NSArray *userList;
- (void)addUser:(IRCUser *)user;
- (void)removeUser:(IRCUser *)user;
- (void)removeUserWithNickname:(NSString *)nickname;
@property (readonly, nullable) IRCUser *myself;
- (NSArray *)findIgnoresForHostmask:(NSString *)hostmask;
#pragma mark -
- (nullable IRCChannel *)findChannel:(NSString *)withName;
- (nullable IRCChannel *)findChannelOrCreate:(NSString *)withName;
- (nullable IRCChannel *)findChannelOrCreate:(NSString *)withName isPrivateMessage:(BOOL)isPrivateMessage;
- (nullable NSData *)convertToCommonEncoding:(NSString *)string;
- (nullable NSString *)convertFromCommonEncoding:(NSData *)data;
- (NSString *)formatNickname:(NSString *)nickname inChannel:(nullable IRCChannel *)channel;
- (NSString *)formatNickname:(NSString *)nickname inChannel:(nullable IRCChannel *)channel withFormat:(nullable NSString *)format;
- (BOOL)nicknameIsZNCUser:(NSString *)nickname;
- (BOOL)nickname:(NSString *)nickname isZNCUser:(NSString *)zncNickname;
- (nullable NSString *)nicknameAsZNCUser:(NSString *)nickname; // Returns nil if not connected to ZNC
- (BOOL)nicknameIsMyself:(NSString *)nickname;
- (BOOL)stringIsNickname:(NSString *)string;
- (BOOL)stringIsChannelName:(NSString *)string;
- (BOOL)outputRuleMatchedInMessage:(NSString *)message inChannel:(nullable IRCChannel *)channel;
#pragma mark -
- (void)setUnreadStateForChannel:(IRCChannel *)channel;
- (void)setUnreadStateForChannel:(IRCChannel *)channel isHighlight:(BOOL)isHighlight;
- (void)setHighlightStateForChannel:(IRCChannel *)channel;
#pragma mark -
- (void)sendCommand:(id)string;
- (void)sendCommand:(id)string completeTarget:(BOOL)completeTarget target:(nullable NSString *)targetChannelName;
- (void)sendCommand:(NSString *)command toZNCModuleNamed:(NSString *)module;
- (void)sendText:(NSAttributedString *)string asCommand:(IRCRemoteCommand)command toChannel:(IRCChannel *)channel;
- (void)sendText:(NSAttributedString *)string asCommand:(IRCRemoteCommand)command toChannel:(IRCChannel *)channel withEncryption:(BOOL)encryptText;
- (void)sendLine:(NSString *)string;
- (void)send:(NSString *)string, ...;
- (void)sendPrivmsg:(NSString *)message toChannel:(IRCChannel *)channel; // Invoke -sendText: with proper values
- (void)sendAction:(NSString *)message toChannel:(IRCChannel *)channel;
- (void)sendNotice:(NSString *)message toChannel:(IRCChannel *)channel;
#pragma mark -
#if TEXTUAL_BUILT_WITH_ADVANCED_ENCRYPTION == 1
- (NSUInteger)lengthOfEncryptedMessageDirectedAt:(NSString *)messageTo thatFitsWithinBounds:(NSUInteger)maximumLength;
- (BOOL)encryptionAllowedForTarget:(NSString *)target;
- (void)encryptMessage:(NSString *)messageBody directedAt:(NSString *)messageTo encodingCallback:(TLOEncryptionManagerEncodingDecodingCallbackBlock)encodingCallback injectionCallback:(TLOEncryptionManagerInjectCallbackBlock)injectionCallback;
- (void)decryptMessage:(NSString *)messageBody from:(NSString *)messageFrom target:(NSString *)target decodingCallback:(TLOEncryptionManagerEncodingDecodingCallbackBlock)decodingCallback;
@property (nonatomic, readonly, copy) NSString * _Nonnull encryptionAccountNameForLocalUser;
- (NSString *)encryptionAccountNameForUser:(NSString *)nickname;
- (void)encryptionAuthenticateUser:(NSString *)nickname;
#endif
#pragma mark -
// nil channel prints the message to the server console
// referenceMessage.command is used if command == nil
// referenceMessage and command cannot be nil together (this throws exceptions)
- (void) print:(NSString *)messageBody
by:(nullable NSString *)nickname
inChannel:(nullable IRCChannel *)channel
asType:(TVCLogLineType)lineType
command:(nullable NSString *)command
receivedAt:(NSDate *)receivedAt
isEncrypted:(BOOL)isEncrypted
escapeMessage:(BOOL)escapeMessage
referenceMessage:(nullable IRCMessage *)referenceMessage
completionBlock:(nullable TVCLogControllerPrintOperationCompletionBlock)completionBlock;
- (void)print:(NSString *)messageBody by:(nullable NSString *)nickname inChannel:(nullable IRCChannel *)channel asType:(TVCLogLineType)lineType command:(NSString *)command;
- (void)print:(NSString *)messageBody by:(nullable NSString *)nickname inChannel:(nullable IRCChannel *)channel asType:(TVCLogLineType)lineType command:(NSString *)command receivedAt:(NSDate *)receivedAt;
- (void)print:(NSString *)messageBody by:(nullable NSString *)nickname inChannel:(nullable IRCChannel *)channel asType:(TVCLogLineType)lineType command:(NSString *)command receivedAt:(NSDate *)receivedAt isEncrypted:(BOOL)isEncrypted;
- (void)print:(NSString *)messageBody by:(nullable NSString *)nickname inChannel:(nullable IRCChannel *)channel asType:(TVCLogLineType)lineType command:(nullable NSString *)command receivedAt:(NSDate *)receivedAt isEncrypted:(BOOL)isEncrypted referenceMessage:(nullable IRCMessage *)referenceMessage;
- (void)print:(NSString *)messageBody by:(nullable NSString *)nickname inChannel:(nullable IRCChannel *)channel asType:(TVCLogLineType)lineType command:(nullable NSString *)command receivedAt:(NSDate *)receivedAt isEncrypted:(BOOL)isEncrypted referenceMessage:(nullable IRCMessage *)referenceMessage completionBlock:(nullable TVCLogControllerPrintOperationCompletionBlock)completionBlock;
- (void)printDebugInformationToConsole:(NSString *)message;
- (void)printDebugInformationToConsole:(NSString *)message asCommand:(NSString *)command;
- (void)printDebugInformation:(NSString *)message;
- (void)printDebugInformation:(NSString *)message asCommand:(NSString *)command;
- (void)printDebugInformation:(NSString *)message inChannel:(IRCChannel *)channel;
- (void)printDebugInformation:(NSString *)message inChannel:(IRCChannel *)channel asCommand:(NSString *)command;
#pragma mark -
- (void)clearCachedHighlights;
/* -config may not always reflect the current state of the client.
* This is because its too costly to mutate it for stuff that changes
* many times a second. The client instead saves a copy of its
* configuration periodically. This method will force it to perform
* a save if you need to rely on most recent version. */
- (void)updateStoredConfiguration;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/IRCClientConfig.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2008 - 2010 Satoshi Nakagawa
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "IRCConnectionConfig.h"
NS_ASSUME_NONNULL_BEGIN
@class IRCAddressBookEntry, IRCChannelConfig, IRCHighlightMatchCondition;
@class IRCNetwork, IRCServer;
#pragma mark -
#pragma mark Immutable Object
@interface IRCClientConfig : XRPortablePropertyDict
@property (readonly) BOOL autoConnect;
@property (readonly) BOOL autoReconnect;
@property (readonly) BOOL autoSleepModeDisconnect;
@property (readonly) BOOL autojoinWaitsForNickServ;
@property (readonly) BOOL hideAutojoinDelayedWarnings;
@property (readonly) BOOL hideNetworkUnavailabilityNotices;
@property (readonly) BOOL performDisconnectOnPongTimer;
@property (readonly) BOOL performDisconnectOnReachabilityChange;
@property (readonly) BOOL performPongTimer;
@property (readonly) BOOL saslAuthenticationDisableExternalMechanism;
@property (readonly) BOOL sendAuthenticationRequestsToUserServ;
@property (readonly) BOOL sendWhoCommandRequestsToChannels;
@property (readonly) BOOL setInvisibleModeOnConnect;
@property (readonly) BOOL sidebarItemExpanded;
@property (readonly) BOOL validateServerCertificateChain;
@property (readonly) BOOL zncIgnoreConfiguredAutojoin;
@property (readonly) BOOL zncIgnorePlaybackNotifications;
@property (readonly) BOOL zncIgnoreUserNotifications;
@property (readonly) BOOL zncOnlyPlaybackLatest;
@property (readonly) IRCConnectionAddressType addressType;
@property (readonly) IRCConnectionProxyType proxyType;
@property (readonly) NSStringEncoding fallbackEncoding;
@property (readonly) NSStringEncoding primaryEncoding;
@property (readonly) NSTimeInterval lastMessageServerTime;
@property (readonly) NSUInteger floodControlDelayTimerInterval;
@property (readonly) NSUInteger floodControlMaximumMessages;
@property (readonly) uint16_t proxyPort;
@property (readonly, copy) NSArray *channelList;
@property (readonly, copy) NSArray *highlightList;
@property (readonly, copy) NSArray *ignoreList;
@property (readonly, copy) NSArray *alternateNicknames;
@property (readonly, copy) NSArray *loginCommands;
@property (readonly, copy) NSArray *serverList;
@property (readonly, copy) NSString *connectionName;
@property (readonly, copy) NSString *nickname;
@property (readonly, copy) NSString *normalLeavingComment;
@property (readonly, copy) NSString *realName;
@property (readonly, copy) NSString *sleepModeLeavingComment;
@property (readonly, copy) NSString *uniqueIdentifier;
@property (readonly, copy) NSString *username;
@property (readonly, copy, nullable) NSData *identityClientSideCertificate;
@property (readonly, copy, nullable) NSString *awayNickname;
@property (readonly, copy, nullable) NSString *nicknamePassword;
@property (readonly, copy, nullable) NSString *nicknamePasswordFromKeychain;
@property (readonly, copy, nullable) NSString *proxyAddress;
@property (readonly, copy, nullable) NSString *proxyPassword;
@property (readonly, copy, nullable) NSString *proxyPasswordFromKeychain;
@property (readonly, copy, nullable) NSString *proxyUsername;
@property (readonly) RCMCipherSuiteCollection cipherSuites;
- (instancetype)initWithDictionary:(NSDictionary *)dic ignorePrivateMessages:(BOOL)ignorePrivateMessages NS_DESIGNATED_INITIALIZER;
+ (instancetype)newConfigByMerging:(IRCClientConfig *)config1 with:(IRCClientConfig *)config2;
+ (instancetype)newConfigWithNetwork:(IRCNetwork *)network;
@end
#pragma mark -
#pragma mark Mutable Object
@interface IRCClientConfigMutable : IRCClientConfig
@property (nonatomic, assign, readwrite) BOOL autoConnect;
@property (nonatomic, assign, readwrite) BOOL autoReconnect;
@property (nonatomic, assign, readwrite) BOOL autoSleepModeDisconnect;
@property (nonatomic, assign, readwrite) BOOL autojoinWaitsForNickServ;
@property (nonatomic, assign, readwrite) BOOL hideAutojoinDelayedWarnings;
@property (nonatomic, assign, readwrite) BOOL hideNetworkUnavailabilityNotices;
@property (nonatomic, assign, readwrite) BOOL performDisconnectOnPongTimer;
@property (nonatomic, assign, readwrite) BOOL performDisconnectOnReachabilityChange;
@property (nonatomic, assign, readwrite) BOOL performPongTimer;
@property (nonatomic, assign, readwrite) BOOL saslAuthenticationDisableExternalMechanism;
@property (nonatomic, assign, readwrite) BOOL sendAuthenticationRequestsToUserServ;
@property (nonatomic, assign, readwrite) BOOL sendWhoCommandRequestsToChannels;
@property (nonatomic, assign, readwrite) BOOL setInvisibleModeOnConnect;
@property (nonatomic, assign, readwrite) BOOL sidebarItemExpanded;
@property (nonatomic, assign, readwrite) BOOL validateServerCertificateChain;
@property (nonatomic, assign, readwrite) BOOL zncIgnoreConfiguredAutojoin;
@property (nonatomic, assign, readwrite) BOOL zncIgnorePlaybackNotifications;
@property (nonatomic, assign, readwrite) BOOL zncIgnoreUserNotifications;
@property (nonatomic, assign, readwrite) BOOL zncOnlyPlaybackLatest;
@property (nonatomic, assign, readwrite) IRCConnectionAddressType addressType;
@property (nonatomic, assign, readwrite) IRCConnectionProxyType proxyType;
@property (nonatomic, assign, readwrite) NSStringEncoding fallbackEncoding;
@property (nonatomic, assign, readwrite) NSStringEncoding primaryEncoding;
@property (nonatomic, assign, readwrite) NSTimeInterval lastMessageServerTime;
@property (nonatomic, assign, readwrite) NSUInteger floodControlDelayTimerInterval;
@property (nonatomic, assign, readwrite) NSUInteger floodControlMaximumMessages;
@property (nonatomic, assign, readwrite) uint16_t proxyPort;
@property (nonatomic, copy, readwrite) NSArray *channelList;
@property (nonatomic, copy, readwrite) NSArray *highlightList;
@property (nonatomic, copy, readwrite) NSArray *ignoreList;
@property (nonatomic, copy, readwrite) NSArray *alternateNicknames;
@property (nonatomic, copy, readwrite) NSArray *loginCommands;
@property (nonatomic, copy, readwrite) NSArray *serverList;
@property (nonatomic, copy, readwrite) NSString *connectionName;
@property (nonatomic, copy, readwrite) NSString *nickname;
@property (nonatomic, copy, readwrite) NSString *normalLeavingComment;
@property (nonatomic, copy, readwrite) NSString *realName;
@property (nonatomic, copy, readwrite) NSString *sleepModeLeavingComment;
@property (nonatomic, copy, readwrite) NSString *username;
@property (nonatomic, copy, readwrite, nullable) NSData *identityClientSideCertificate;
@property (nonatomic, copy, readwrite, nullable) NSString *awayNickname;
@property (nonatomic, copy, readwrite, nullable) NSString *nicknamePassword;
@property (nonatomic, copy, readwrite, nullable) NSString *proxyAddress;
@property (nonatomic, copy, readwrite, nullable) NSString *proxyPassword;
@property (nonatomic, copy, readwrite, nullable) NSString *proxyUsername;
@property (nonatomic, assign, readwrite) RCMCipherSuiteCollection cipherSuites;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/IRCColorFormat.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2008 - 2010 Satoshi Nakagawa
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
NS_ASSUME_NONNULL_BEGIN
typedef NS_ENUM(NSUInteger, IRCTextFormatterEffectType) {
IRCTextFormatterEffectNone = 0,
IRCTextFormatterEffectBold,
IRCTextFormatterEffectItalic,
IRCTextFormatterEffectMonospace,
IRCTextFormatterEffectStrikethrough,
IRCTextFormatterEffectUnderline,
IRCTextFormatterEffectForegroundColor,
IRCTextFormatterEffectBackgroundColor,
IRCTextFormatterEffectSpoiler,
};
typedef NSString *IRCTextFormatterAttributeName NS_EXTENSIBLE_STRING_ENUM;
TEXTUAL_EXTERN IRCTextFormatterAttributeName const IRCTextFormatterBoldAttributeName; // BOOL
TEXTUAL_EXTERN IRCTextFormatterAttributeName const IRCTextFormatterItalicAttributeName; // BOOL
TEXTUAL_EXTERN IRCTextFormatterAttributeName const IRCTextFormatterMonospaceAttributeName; // BOOL
TEXTUAL_EXTERN IRCTextFormatterAttributeName const IRCTextFormatterStrikethroughAttributeName; // BOOL
TEXTUAL_EXTERN IRCTextFormatterAttributeName const IRCTextFormatterUnderlineAttributeName; // BOOL
TEXTUAL_EXTERN IRCTextFormatterAttributeName const IRCTextFormatterForegroundColorAttributeName; // NSNumber, 0-15 - or, NSColor
TEXTUAL_EXTERN IRCTextFormatterAttributeName const IRCTextFormatterBackgroundColorAttributeName; // NSNumber, 0-15 - or, NSColor
TEXTUAL_EXTERN IRCTextFormatterAttributeName const IRCTextFormatterSpoilerAttributeName; // BOOL
#define IRCTextFormatterEffectColorAsDigitCharacter 0x03
#define IRCTextFormatterEffectColorAsHexCharacter 0x04
#define IRCTextFormatterEffectBoldCharacter 0x02
#define IRCTextFormatterEffectItalicCharacter 0x1d
#define IRCTextFormatterEffectItalicCharacterOld 0x16
#define IRCTextFormatterEffectMonospaceCharacter 0x11
#define IRCTextFormatterEffectStrikethroughCharacter 0x1e
#define IRCTextFormatterEffectUnderlineCharacter 0x1F
#define IRCTextFormatterTerminatingCharacter 0x0F
#define IRCTextFormatterEffectColorHighestDigit 98
@class IRCTextFormatterEffects;
@interface IRCTextFormatterEffect : NSObject
@property (readonly) IRCTextFormatterEffectType type;
@property (readonly, copy, nullable) NSString *value;
@property (readonly) UniChar controlCharacter;
/* Number of bytes needed to support this effect.
Open control character + value + close control character.
For background color, only the comma and color value is counted. */
@property (readonly) NSUInteger length;
+ (nullable instancetype)effectWithType:(IRCTextFormatterEffectType)type;
+ (nullable instancetype)effectWithType:(IRCTextFormatterEffectType)type withValue:(nullable id)value;
- (nullable instancetype)initWithEffect:(IRCTextFormatterEffectType)type;
- (nullable instancetype)initWithEffect:(IRCTextFormatterEffectType)type withValue:(nullable id)value NS_DESIGNATED_INITIALIZER;
/* Appends control character and value for the effect.
For background color, appends comma and color value instead. */
- (void)appendToStartOf:(NSMutableString *)string;
/* Appends control character for the effect.
For background color, does nothing. */
- (void)appendToEndOf:(NSMutableString *)string;
@end
@interface IRCTextFormatterEffects : NSObject
@property (readonly, copy) NSArray *effects;
/* Number of bytes needed to support all effects. */
@property (readonly) NSUInteger maximumLength;
+ (instancetype)effectsInAttributes:(NSDictionary *)attributes;
- (instancetype)initWithAttributes:(NSDictionary *)attributes NS_DESIGNATED_INITIALIZER;
- (void)appendToStartOf:(NSMutableString *)string;
- (void)appendToEndOf:(NSMutableString *)string;
@end
#pragma mark -
@interface NSAttributedString (IRCTextFormatter)
- (BOOL)IRCFormatterAttributeSetInRange:(IRCTextFormatterEffectType)effect
range:(NSRange)limitRange;
/* Returns an NSString with appropriate formatting characters. */
@property (readonly, copy) NSString *stringFormattedForIRC;
@end
#pragma mark -
@interface NSMutableAttributedString (IRCTextFormatter)
- (void)setIRCFormatterAttribute:(IRCTextFormatterEffectType)effect
value:(id)value
range:(NSRange)limitRange;
- (void)removeIRCFormatterAttribute:(IRCTextFormatterEffectType)effect
range:(NSRange)limitRange;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/IRCCommandIndex.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2019 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
NS_ASSUME_NONNULL_BEGIN
/* Local commands are client-local commands */
typedef NS_ENUM(NSUInteger, IRCLocalCommand) {
IRCLocalCommandAdchat = 5001,
IRCLocalCommandAme = 5002,
IRCLocalCommandAmsg = 5003,
IRCLocalCommandAquote = 5095,
IRCLocalCommandAraw = 5096,
IRCLocalCommandAutojoin = 5101,
IRCLocalCommandAway = 5004,
IRCLocalCommandBack = 5105,
IRCLocalCommandBan = 5005,
IRCLocalCommandCap = 5006,
IRCLocalCommandCaps = 5007,
IRCLocalCommandChatops = 5009,
IRCLocalCommandClear = 5010,
IRCLocalCommandClearall = 5011,
IRCLocalCommandClose = 5012,
IRCLocalCommandConn = 5013,
IRCLocalCommandCtcp = 5014,
IRCLocalCommandCtcpreply = 5015,
IRCLocalCommandCycle = 5016,
IRCLocalCommandDcc = 5017,
IRCLocalCommandDebug = 5018,
IRCLocalCommandDefaults = 5092,
IRCLocalCommandDehalfop = 5019,
IRCLocalCommandDeop = 5020,
IRCLocalCommandDevoice = 5021,
IRCLocalCommandEcho = 5022,
IRCLocalCommandGetscripts = 5098,
IRCLocalCommandGline = 5023,
IRCLocalCommandGlobops = 5024,
IRCLocalCommandGoto = 5099,
IRCLocalCommandGzline = 5025,
IRCLocalCommandHalfop = 5026,
IRCLocalCommandHop = 5027,
IRCLocalCommandIgnore = 5029,
IRCLocalCommandInvite = 5030,
IRCLocalCommandIson = 5100,
IRCLocalCommandJ = 5031,
IRCLocalCommandJoin = 5032,
IRCLocalCommandJoinRandom = 5109,
IRCLocalCommandKb = 5083,
IRCLocalCommandKick = 5033,
IRCLocalCommandKickban = 5034,
IRCLocalCommandKill = 5035,
IRCLocalCommandLagcheck = 5084,
IRCLocalCommandLeave = 5036,
IRCLocalCommandList = 5037,
IRCLocalCommandLocops = 5039,
IRCLocalCommandM = 5040,
IRCLocalCommandMe = 5041,
IRCLocalCommandMode = 5042,
IRCLocalCommandMonitor = 5106,
IRCLocalCommandMsg = 5043,
IRCLocalCommandMute = 5044,
IRCLocalCommandMylag = 5045,
IRCLocalCommandMyversion = 5046,
IRCLocalCommandNachat = 5047,
IRCLocalCommandNames = 5094,
IRCLocalCommandNick = 5048,
IRCLocalCommandNotice = 5050,
IRCLocalCommandNotifybubble = 5112,
IRCLocalCommandNotifysound = 5113,
IRCLocalCommandNotifyspeak = 5114,
IRCLocalCommandOmsg = 5051,
IRCLocalCommandOnotice = 5052,
IRCLocalCommandOp = 5053,
IRCLocalCommandPart = 5054,
IRCLocalCommandPass = 5055,
IRCLocalCommandQuery = 5056,
IRCLocalCommandQuiet = 5107,
IRCLocalCommandQuit = 5057,
IRCLocalCommandQuote = 5058,
IRCLocalCommandRaw = 5059,
IRCLocalCommandRecv = 5087,
IRCLocalCommandRejoin = 5060,
IRCLocalCommandRemove = 5061,
IRCLocalCommandServer = 5062,
IRCLocalCommandSetcolor = 5103,
IRCLocalCommandSetqueryname = 5117,
IRCLocalCommandShun = 5063,
IRCLocalCommandSme = 5064,
IRCLocalCommandSmsg = 5065,
IRCLocalCommandSslcontext = 5066,
IRCLocalCommandT = 5067,
IRCLocalCommandTage = 5093,
IRCLocalCommandTempshun = 5068,
IRCLocalCommandTimer = 5069,
IRCLocalCommandTopic = 5070,
IRCLocalCommandUme = 5089,
IRCLocalCommandUmode = 5071,
IRCLocalCommandUmsg = 5088,
IRCLocalCommandUnban = 5072,
IRCLocalCommandUnignore = 5073,
IRCLocalCommandUnmute = 5075,
IRCLocalCommandUnotice = 5090,
IRCLocalCommandUnquiet = 5108,
IRCLocalCommandVoice = 5076,
IRCLocalCommandWallops = 5077,
IRCLocalCommandWatch = 5097,
IRCLocalCommandWeights = 5118,
IRCLocalCommandWho = 5079,
IRCLocalCommandWhois = 5080,
IRCLocalCommandWhowas = 5081,
IRCLocalCommandZline = 5082
};
/* Remote commands are server-side commands */
typedef NS_ENUM(NSUInteger, IRCRemoteCommand) {
IRCRemoteCommandAdchat = 1003,
IRCRemoteCommandAuthenticate = 1005,
IRCRemoteCommandAway = 1050,
IRCRemoteCommandBatch = 1054,
IRCRemoteCommandCap = 1004,
IRCRemoteCommandCertinfo = 1055,
IRCRemoteCommandChatops = 1006,
IRCRemoteCommandChghost = 1057,
IRCRemoteCommandError = 1016,
IRCRemoteCommandGline = 1047,
IRCRemoteCommandGlobops = 1017,
IRCRemoteCommandGzline = 1048,
IRCRemoteCommandInvite = 1018,
IRCRemoteCommandIson = 1019,
IRCRemoteCommandJoin = 1020,
IRCRemoteCommandKick = 1021,
IRCRemoteCommandKill = 1022,
IRCRemoteCommandList = 1023,
IRCRemoteCommandLocops = 1024,
IRCRemoteCommandMode = 1026,
IRCRemoteCommandMonitor = 1056,
IRCRemoteCommandNachat = 1027,
IRCRemoteCommandNames = 1028,
IRCRemoteCommandNick = 1029,
IRCRemoteCommandNotice = 1030,
IRCRemoteCommandPart = 1031,
IRCRemoteCommandPass = 1032,
IRCRemoteCommandPing = 1033,
IRCRemoteCommandPong = 1034,
IRCRemoteCommandPrivmsg = 1035,
IRCRemoteCommandPrivmsgAction = 1002,
IRCRemoteCommandQuit = 1036,
IRCRemoteCommandShun = 1045,
IRCRemoteCommandTempshun = 1046,
IRCRemoteCommandTime = 1012,
IRCRemoteCommandTopic = 1039,
IRCRemoteCommandUser = 1037,
IRCRemoteCommandWallops = 1038,
IRCRemoteCommandWatch = 1053,
IRCRemoteCommandWho = 1040,
IRCRemoteCommandWhois = 1042,
IRCRemoteCommandWhowas = 1041,
IRCRemoteCommandZline = 1049
};
/* Controlling class */
@interface IRCCommandIndex : NSObject
+ (NSArray *)localCommandList;
+ (NSUInteger)indexOfRemoteCommand:(NSString *)command;
+ (NSUInteger)indexOfLocalCommand:(NSString *)command;
+ (NSUInteger)colonPositionForRemoteCommand:(NSString *)command;
+ (nullable NSString *)syntaxForLocalCommand:(NSString *)command;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/IRCConnection.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2008 - 2010 Satoshi Nakagawa
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
NS_ASSUME_NONNULL_BEGIN
@class IRCClient, IRCConnectionConfig;
@interface IRCConnection : NSObject
@property (readonly, weak) IRCClient *client;
@property (readonly, copy) IRCConnectionConfig *config;
@property (readonly) BOOL isConnected;
@property (readonly) BOOL isConnectedWithClientSideCertificate;
@property (readonly) BOOL isConnecting;
@property (readonly) BOOL isDisconnecting;
@property (readonly) BOOL isSecured;
@property (readonly) BOOL isSending;
@property (readonly) BOOL EOFReceived;
@property (readonly, nullable) NSString *connectedAddress; // nil if connected to a proxy
@property (readonly, copy) NSString *uniqueIdentifier;
- (instancetype)init NS_UNAVAILABLE;
- (instancetype)initWithConfig:(IRCConnectionConfig *)config onClient:(IRCClient *)client NS_DESIGNATED_INITIALIZER;
- (void)open;
- (void)close;
- (void)sendLine:(NSString *)line;
- (void)clearSendQueue;
@end
@protocol IRCConnectionDelegate
@required
- (void)ircConnection:(IRCConnection *)sender
willConnectToProxy:(NSString *)proxyHost
port:(uint16_t)proxyPort;
- (void)ircConnectionDidConnect:(IRCConnection *)sender;
- (void)ircConnectionDidSecureConnection:(IRCConnection *)sender
withProtocolType:(tls_protocol_version_t)protocolType
cipherSuite:(tls_ciphersuite_t)cipherSuite;
- (void)ircConnectionDidCloseReadStream:(IRCConnection *)sender;
- (void)ircConnection:(IRCConnection *)sender didDisconnectWithError:(nullable NSError *)disconnectError;
- (void)ircConnection:(IRCConnection *)sender didReceiveData:(NSString *)data;
- (void)ircConnection:(IRCConnection *)sender willSendData:(NSString *)data;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/IRCHighlightLogEntry.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
NS_ASSUME_NONNULL_BEGIN
@class TVCLogLine;
@interface IRCHighlightLogEntry : XRPortablePropertyObject
@property (readonly, copy) TVCLogLine *lineLogged;
@property (readonly, copy) NSDate *timeLogged;
@property (readonly, copy) NSString *clientId;
@property (readonly, copy) NSString *channelId;
@property (readonly, copy) NSString *lineNumber;
@property (readonly, copy) NSAttributedString *renderedMessage;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/IRCHighlightMatchCondition.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
NS_ASSUME_NONNULL_BEGIN
#pragma mark -
#pragma mark Immutable Object
@interface IRCHighlightMatchCondition : XRPortablePropertyDict
@property (readonly, copy) NSString *uniqueIdentifier;
@property (readonly, copy) NSString *matchKeyword;
@property (readonly, copy, nullable) NSString *matchChannelId;
@property (readonly) BOOL matchIsExcluded;
@end
#pragma mark -
#pragma mark Mutable Object
@interface IRCHighlightMatchConditionMutable : IRCHighlightMatchCondition
@property (nonatomic, copy, readwrite) NSString *matchKeyword;
@property (nonatomic, copy, readwrite, nullable) NSString *matchChannelId;
@property (nonatomic, assign, readwrite) BOOL matchIsExcluded;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/IRCISupportInfo.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2008 - 2010 Satoshi Nakagawa
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
NS_ASSUME_NONNULL_BEGIN
@class IRCModeInfo;
typedef NS_ENUM(NSUInteger, IRCISupportInfoListType)
{
IRCISupportInfoListTypeBan,
IRCISupportInfoListTypeBanException,
IRCISupportInfoListTypeInviteException,
IRCISupportInfoListTypeQuiet
};
#define IRCISupportInfoHighestUserPrefixRank 100
#define IRCISupportUserModeSymbolsSymbolsKey @"modeSymbols"
#define IRCISupportUserModeSymbolsCharactersKey @"characters"
@interface IRCISupportInfo : NSObject
@property (readonly) BOOL configurationReceived;
@property (readonly) NSUInteger maximumAwayLength; // 0 = no limit
@property (readonly) NSUInteger maximumChannelNameLength; // 0 = no limit - unused
@property (readonly) NSUInteger maximumKeyLength; // 0 = no limit
@property (readonly) NSUInteger maximumKickLength; // 0 = no limit
@property (readonly) NSUInteger maximumNicknameLength;
@property (readonly) NSUInteger maximumTopicLength; // 0 = no limit
@property (readonly) NSUInteger maximumModeCount;
@property (readonly, copy) NSArray *channelNamePrefixes;
@property (readonly, copy) NSArray *statusMessageModeSymbols;
@property (readonly, copy) NSDictionary *channelModes;
@property (readonly, copy) NSDictionary *userModeSymbols;
@property (readonly, copy, nullable) NSString *banExceptionModeSymbol;
@property (readonly, copy, nullable) NSString *inviteExceptionModeSymbol;
@property (readonly, copy, nullable) NSString *serverAddress;
@property (readonly, copy, nullable) NSString *networkName;
@property (readonly, copy, nullable) NSString *networkNameFormatted;
- (instancetype)init NS_UNAVAILABLE;
- (nullable NSString *)modeSymbolForUserPrefix:(NSString *)character;
- (nullable NSString *)userPrefixForModeSymbol:(NSString *)modeSymbol;
- (BOOL)characterIsUserPrefix:(NSString *)character;
- (BOOL)modeSymbolIsUserPrefix:(NSString *)modeSymbol;
- (nullable NSString *)statusMessagePrefixForModeSymbol:(NSString *)modeSymbol;
- (NSString *)extractStatusMessagePrefixFromChannelNamed:(NSString *)channel;
- (NSUInteger)rankForUserPrefixWithMode:(NSString *)modeSymbol; // Starts at 100; 100 = highest rank
- (IRCModeInfo *)createModeWithSymbol:(NSString *)modeSymbol;
- (IRCModeInfo *)createModeWithSymbol:(NSString *)modeSymbol modeIsSet:(BOOL)modeIsSet modeParameter:(nullable NSString *)modeParameter;
- (BOOL)isListSupported:(IRCISupportInfoListType)listType;
- (nullable NSString *)modeSymbolForList:(IRCISupportInfoListType)listType;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/IRCMessage.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2008 - 2010 Satoshi Nakagawa
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
NS_ASSUME_NONNULL_BEGIN
@class IRCClient, IRCPrefix;
#pragma mark -
#pragma mark Immutable Object
@interface IRCMessage : XRPortablePropertyObject
@property (readonly, copy) IRCPrefix *sender;
@property (readonly, copy) NSString *command;
@property (readonly) NSUInteger commandNumeric;
@property (readonly, copy) NSArray *params;
@property (readonly, copy) NSDate *receivedAt;
@property (readonly) BOOL isHistoric; // Whether a custom @time= was supplied during parsing.
@property (readonly) BOOL isEventOnlyMessage; /* The message should be parsed and special actions performed such as adding/removing user but the result is never passed to print: */
@property (readonly) BOOL isPrintOnlyMessage; /* The message should be parsed and passed to print: but special actions such as adding/removing user from member list should be ignored. (currently unused) */
@property (readonly, copy, nullable) NSString *batchToken;
@property (readonly, copy, nullable) NSDictionary *messageTags; /* IRCv3 message tags. See ircv3.net for more information regarding extensions in the IRC protocol. */
- (nullable instancetype)initWithLine:(NSString *)line;
- (nullable instancetype)initWithLine:(NSString *)line onClient:(nullable IRCClient *)client NS_DESIGNATED_INITIALIZER;
@property (readonly, copy, nullable) NSString *senderNickname;
@property (readonly, copy, nullable) NSString *senderUsername;
@property (readonly, copy, nullable) NSString *senderAddress;
@property (readonly, copy, nullable) NSString *senderHostmask;
@property (readonly) BOOL senderIsServer;
@property (readonly) NSUInteger paramsCount;
- (NSString *)paramAt:(NSUInteger)index;
@property (readonly, copy) NSString *sequence;
- (NSString *)sequence:(NSUInteger)index;
@end
#pragma mark -
#pragma mark Mutable Object
@interface IRCMessageMutable : IRCMessage
@property (nonatomic, copy, readwrite) IRCPrefix *sender;
@property (nonatomic, copy, readwrite) NSString *command;
@property (nonatomic, assign, readwrite) NSUInteger commandNumeric;
@property (nonatomic, copy, readwrite) NSArray *params;
@property (nonatomic, copy, readwrite) NSDate *receivedAt;
@property (nonatomic, assign, readwrite) BOOL isHistoric;
@property (nonatomic, assign, readwrite) BOOL isEventOnlyMessage;
@property (nonatomic, assign, readwrite) BOOL isPrintOnlyMessage;
@property (nonatomic, copy, readwrite, nullable) NSString *batchToken;
@property (nonatomic, copy, readwrite, nullable) NSDictionary *messageTags;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/IRCModeInfo.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2008 - 2010 Satoshi Nakagawa
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
NS_ASSUME_NONNULL_BEGIN
@class IRCClient;
#pragma mark -
#pragma mark Immutable Object
@interface IRCModeInfo : XRPortablePropertyObject
@property (readonly) BOOL modeIsSet;
@property (readonly, copy) NSString *modeSymbol;
@property (readonly, copy, nullable) NSString *modeParameter;
- (instancetype)init NS_UNAVAILABLE;
- (instancetype)initWithModeSymbol:(NSString *)modeSymbol;
- (instancetype)initWithModeSymbol:(NSString *)modeSymbol modeIsSet:(BOOL)modeIsSet;
- (instancetype)initWithModeSymbol:(NSString *)modeSymbol modeIsSet:(BOOL)modeIsSet modeParameter:(nullable NSString *)modeParameter NS_DESIGNATED_INITIALIZER;
- (BOOL)isModeForChangingMemberModeOn:(IRCClient *)client;
@end
#pragma mark -
#pragma mark Mutable Object
@interface IRCModeInfoMutable : IRCModeInfo
@property (nonatomic, assign, readwrite) BOOL modeIsSet;
@property (nonatomic, copy, readwrite) NSString *modeSymbol;
@property (nonatomic, copy, readwrite, nullable) NSString *modeParameter;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/IRCNetworkList.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
NS_ASSUME_NONNULL_BEGIN
@class IRCNetwork;
@interface IRCNetworkList : NSObject
@property (readonly, copy) NSArray *listOfNetworks;
- (nullable IRCNetwork *)networkNamed:(NSString *)networkName;
- (nullable IRCNetwork *)networkWithServerAddress:(NSString *)serverAddress;
@end
#pragma mark -
@interface IRCNetwork : NSObject
@property (readonly, copy) NSString *networkName;
@property (readonly, copy) NSString *networkDescription NS_UNAVAILABLE; // unused
@property (readonly, copy) NSString *serverAddress;
@property (readonly) uint16_t serverPort;
@property (readonly) BOOL prefersSecuredConnection;
- (instancetype)init NS_UNAVAILABLE;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/IRCNumerics.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
enum {
/* Replies */
RPL_WELCOME = 1,
RPL_YOURHOST = 2,
RPL_CREATED = 3,
RPL_MYINFO = 4,
RPL_ISUPPORT = 5,
RPL_REDIR = 10,
RPL_UMODEIS = 221,
RPL_STATSCONN = 250,
RPL_LUSERCLIENT = 251,
RPL_LUSERHOP = 252,
RPL_LUSERUNKNOWN = 253,
RPL_LUSERCHANNELS = 254,
RPL_LUSERME = 255,
RPL_LOCALUSERS = 265,
RPL_GLOBALUSERS = 266,
RPL_WHOISCERTFP = 276,
RPL_AWAY = 301,
RPL_ISON = 303,
RPL_UNAWAY = 305,
RPL_NOWAWAY = 306,
RPL_WHOISREGNICK = 307,
RPL_WHOISHELPOP = 310,
RPL_WHOISUSER = 311,
RPL_WHOISSERVER = 312,
RPL_WHOISOPERATOR = 313,
RPL_WHOWASUSER = 314,
RPL_ENDOFWHO = 315,
RPL_WHOISIDLE = 317,
RPL_ENDOFWHOIS = 318,
RPL_WHOISCHANNELS = 319,
RPL_WHOISSPECIAL = 320,
RPL_LISTSTART = 321,
RPL_LIST = 322,
RPL_LISTEND = 323,
RPL_CHANNELMODEIS = 324,
RPL_CHANNEL_URL = 328,
RPL_CREATIONTIME = 329,
RPL_WHOISACCOUNT = 330,
RPL_TOPIC = 332,
RPL_TOPICWHOTIME = 333,
RPL_WHOISBOT = 335,
RPL_WHOISACTUALLY = 338,
RPL_INVITING = 341,
RPL_INVITELIST = 346,
RPL_ENDOFINVITELIST = 347,
RPL_EXCEPTLIST = 348,
RPL_ENDOFEXCEPTLIST = 349,
RPL_WHOREPLY = 352,
RPL_NAMEREPLY = 353,
RPL_ENDOFNAMES = 366,
RPL_BANLIST = 367,
RPL_ENDOFBANLIST = 368,
RPL_ENDOFWHOWAS = 369,
RPL_MOTD = 372,
RPL_MOTDSTART = 375,
RPL_ENDOFMOTD = 376,
RPL_WHOISHOST = 378,
RPL_WHOISMODES = 379,
RPL_YOUREOPER = 381,
RPL_REAWAY = 597,
RPL_GONEAWAY = 598,
RPL_NOTAWAY = 599,
RPL_LOGON = 600,
RPL_LOGOFF = 601,
RPL_WATCHOFF = 602,
RPL_WATCHSTAT = 603,
RPL_NOWON = 604,
RPL_NOWOFF = 605,
RPL_WATCHLIST = 606,
RPL_ENDOFWATCHLIST = 607,
RPL_CLEARWATCH = 608,
/* RPL_CHANNELSMSG and RPL_WHOWASIP were added recently.
Reference: https://github.com/inspircd/inspircd/commit/150258b1f110aad58c8882b76474a4ceb3b2ab97 */
RPL_CHANNELSMSG = 651, // (is on private/secret channels..., InspIRCd)
RPL_WHOWASIP = 652, // (was connected from..., InspIRCd)
RPL_WHOISSECURE = 671,
RPL_WHOISREALIP = 672, // (is a CGI:IRC client from..., Rizon)
RPL_TARGUMODEG = 716,
RPL_TARGNOTIFY = 717,
RPL_UMODEGMSG = 718,
RPL_QUIETLIST = 728,
RPL_ENDOFQUIETLIST = 729,
RPL_MONONLINE = 730,
RPL_MONOFFLINE = 731,
RPL_MONLIST = 732,
RPL_ENDOFMONLIST = 733,
RPL_LOGGEDIN = 900,
RPL_LOGGEDOUT = 901,
RPL_SASLSUCCESS = 903,
RPL_SASLMECHS = 908,
/* Errors */
ERR_NOSUCHNICK = 401,
ERR_NOSUCHSERVER = 402,
ERR_NOSUCHCHANNEL = 403,
ERR_CANNOTSENDTOCHAN = 404,
ERR_TOOMANYCHANNELS = 405,
ERR_UNKNOWNCOMMAND = 421,
ERR_NOMOTD = 422,
ERR_ERRONEUSNICKNAME = 432,
ERR_NICKNAMEINUSE = 433,
ERR_BANNICKCHANGE = 435,
ERR_UNAVAILRESOURCE = 437,
ERR_NICKTOOFAST = 438,
ERR_CANTCHANGENICK = 447,
ERR_FORBIDDENCHANNEL = 448,
ERR_NOHIDING = 459,
ERR_NEEDMOREPARAMS = 461,
ERR_LINKCHANNEL = 470,
ERR_CHANNELISFULL = 471,
ERR_INVITEONLYCHAN = 473,
ERR_BANNEDFROMCHAN = 474,
ERR_BADCHANNELKEY = 475,
ERR_BADCHANMASK = 476,
ERR_NEEDREGGEDNICK = 477,
ERR_BADCHANNAME = 479,
ERR_THROTTLE = 480,
ERR_SECUREONLYCHAN = 489,
ERR_DELAYREJOIN = 495,
ERR_TOOMANYJOINS = 500,
ERR_TOOMANYWATCH = 512,
ERR_DISABLED = 517,
ERR_ADMONLY = 519,
ERR_OPERONLY = 520,
ERR_WHOSYNTAX = 522,
ERR_WHOLIMEXCEED = 523,
ERR_OPERSPVERIFY = 524,
ERR_MONLISTFULL = 734,
ERR_NICKLOCKED = 902,
ERR_SASLFAIL = 904,
ERR_SASLTOOLONG = 905,
ERR_SASLABORTED = 906,
ERR_SASLALREADY = 907,
ERR_BADCHANNEL = 926
};
================================================
FILE: Sources/App/Classes/Headers/IRCPrefix.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2008 - 2010 Satoshi Nakagawa
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
NS_ASSUME_NONNULL_BEGIN
#pragma mark -
#pragma mark Immutable Object
@interface IRCPrefix : XRPortablePropertyObject
@property (readonly) BOOL isServer;
@property (readonly, copy) NSString *hostmask; // Defaults to empty string
@property (readonly, copy) NSString *nickname; // Defaults to empty string
@property (readonly, copy, nullable) NSString *username;
@property (readonly, copy, nullable) NSString *address;
@end
#pragma mark -
#pragma mark Mutable Object
@interface IRCPrefixMutable : IRCPrefix
@property (nonatomic, assign, readwrite) BOOL isServer;
@property (nonatomic, copy, readwrite) NSString *hostmask;
@property (nonatomic, copy, readwrite) NSString *nickname;
@property (nonatomic, copy, readwrite, nullable) NSString *username;
@property (nonatomic, copy, readwrite, nullable) NSString *address;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/IRCSendingMessage.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2008 - 2010 Satoshi Nakagawa
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
NS_ASSUME_NONNULL_BEGIN
@interface IRCSendingMessage : NSObject
+ (NSString *)stringWithCommand:(NSString *)command arguments:(nullable NSArray *)arguments;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/IRCServer.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
NS_ASSUME_NONNULL_BEGIN
#pragma mark -
#pragma mark Immutable Object
@interface IRCServer : XRPortablePropertyDict
@property (readonly, copy) NSString *uniqueIdentifier;
@property (readonly, copy) NSString *serverAddress;
@property (readonly, copy, nullable) NSString *serverPassword;
@property (readonly, copy, nullable) NSString *serverPasswordFromKeychain;
@property (readonly) uint16_t serverPort;
@property (readonly) BOOL prefersSecuredConnection;
@end
#pragma mark -
#pragma mark Mutable Object
@interface IRCServerMutable : IRCServer
@property (nonatomic, copy, readwrite) NSString *serverAddress;
@property (nonatomic, copy, readwrite, nullable) NSString *serverPassword;
@property (nonatomic, assign, readwrite) uint16_t serverPort;
@property (nonatomic, assign, readwrite) BOOL prefersSecuredConnection;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/IRCTreeItem.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2008 - 2010 Satoshi Nakagawa
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
NS_ASSUME_NONNULL_BEGIN
@class IRCClient, IRCChannel, TVCLogController;
@interface IRCTreeItem : NSObject
@property (readonly) BOOL isActive;
@property (readonly) BOOL isUnread;
@property (readonly) BOOL isClient;
@property (readonly) BOOL isChannel;
@property (readonly) BOOL isPrivateMessage;
@property (readonly, weak) IRCClient *associatedClient;
@property (readonly, weak) IRCChannel *associatedChannel;
@property (readonly) NSString *label;
@property (readonly) NSString *name;
@property (readonly) NSString *uniqueIdentifier;
@property (readonly) NSUInteger dockUnreadCount;
@property (readonly) NSUInteger nicknameHighlightCount;
@property (readonly) NSUInteger treeUnreadCount;
@property (readonly) TVCLogController *viewController;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/IRCUser.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2008 - 2010 Satoshi Nakagawa
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
/* Each user on a server is allocated one instance of IRCUser.
IRCUser is used to keep track of information related to the user. */
/* There is ever only one instance of IRCUser kept track of by the
IRCClient class. It is possible to create a mutable copy of a user
to change properties, but those changes will not be recognized until
the modified user is given to IRCClient. IRCClient will then perform
the actions necessary to update all components depending on the user. */
NS_ASSUME_NONNULL_BEGIN
@class IRCClient;
#pragma mark -
#pragma mark Immutable Object
@interface IRCUser : XRPortablePropertyObject
@property (readonly, copy) NSString *nickname;
@property (readonly, copy, nullable) NSString *username;
@property (readonly, copy, nullable) NSString *address;
@property (readonly, copy, nullable) NSString *hostmask;
@property (readonly, copy, nullable) NSString *hostmaskFragment; // -hostmask without nickname
@property (readonly, copy, nullable) NSString *realName;
@property (readonly) BOOL isAway;
@property (readonly) BOOL isIRCop;
@property (readonly, copy) NSString *banMask;
@property (readonly, copy) NSString *lowercaseNickname;
@property (readonly, copy) NSString *uppercaseNickname;
/* -presentAwayMessageFor301 keeps track of the last time raw numeric
301 (away message) is received and will return YES if the message
should be presented, NO otherwise. */
@property (readonly) BOOL presentAwayMessageFor301;
- (instancetype)init NS_UNAVAILABLE;
- (instancetype)initWithNickname:(NSString *)nickname onClient:(IRCClient *)client NS_DESIGNATED_INITIALIZER;
- (void)markAsAway;
- (void)markAsReturned;
@end
#pragma mark -
#pragma mark Mutable Object
@interface IRCUserMutable : IRCUser
@property (nonatomic, copy, readwrite) NSString *nickname; // Defaults to empty string
@property (nonatomic, copy, readwrite, nullable) NSString *username;
@property (nonatomic, copy, readwrite, nullable) NSString *address;
@property (nonatomic, copy, readwrite, nullable) NSString *realName;
@property (nonatomic, assign, readwrite) BOOL isAway;
@property (nonatomic, assign, readwrite) BOOL isIRCop;
- (instancetype)initWithClient:(IRCClient *)client;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/IRCUserRelations.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "IRCUser.h"
NS_ASSUME_NONNULL_BEGIN
@class IRCChannel, IRCChannelUser;
@interface IRCUser (IRCUserRelations)
@property (readonly, copy) NSDictionary *relations;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/IRCWorld.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2008 - 2010 Satoshi Nakagawa
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
NS_ASSUME_NONNULL_BEGIN
@class IRCClient, IRCClientConfig, IRCChannel, IRCChannelConfig, IRCTreeItem;
TEXTUAL_EXTERN NSString * const IRCWorldClientListDefaultsKey;
TEXTUAL_EXTERN NSNotificationName const IRCWorldClientListWasModifiedNotification;
TEXTUAL_EXTERN NSNotificationName const IRCWorldDateHasChangedNotification;
TEXTUAL_EXTERN NSNotificationName const IRCWorldWillDestroyClientNotification;
TEXTUAL_EXTERN NSNotificationName const IRCWorldWillDestroyChannelNotification;
@interface IRCWorld : NSObject
@property (readonly) NSUInteger messagesSent;
@property (readonly) NSUInteger messagesReceived;
@property (readonly) uint64_t bandwidthIn;
@property (readonly) uint64_t bandwidthOut;
@property (readonly, copy) NSArray *clientList;
@property (readonly) NSUInteger clientCount;
- (void)save;
- (void)savePeriodically;
- (NSArray<__kindof IRCTreeItem *> *)findItemsWithIds:(NSArray *)itemIds;
- (nullable IRCTreeItem *)findItemWithId:(NSString *)itemId;
- (nullable IRCClient *)findClientWithId:(NSString *)clientId;
- (nullable IRCChannel *)findChannelWithId:(NSString *)channelId onClientWithId:(NSString *)clientId;
- (nullable IRCClient *)findClientWithServerAddress:(NSString *)serverAddress;
- (IRCClient *)createClientWithConfig:(IRCClientConfig *)config;
- (IRCChannel *)createChannelWithConfig:(IRCChannelConfig *)config onClient:(IRCClient *)client;
- (IRCChannel *)createPrivateMessage:(NSString *)nickname onClient:(IRCClient *)client;
- (void)destroyClient:(IRCClient *)client;
- (void)destroyChannel:(IRCChannel *)channel;
- (void)evaluateFunctionOnAllViews:(NSString *)function arguments:(nullable NSArray *)arguments; // Defaults to onQueue YES
- (void)evaluateFunctionOnAllViews:(NSString *)function arguments:(nullable NSArray *)arguments onQueue:(BOOL)onQueue;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Internal/IRCAddressBookInternal.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "IRCAddressBook.h"
NS_ASSUME_NONNULL_BEGIN
@interface IRCAddressBookEntry ()
{
@protected
BOOL _ignoreClientToClientProtocol;
BOOL _ignoreFileTransferRequests;
BOOL _ignoreGeneralEventMessages;
BOOL _ignoreInlineMedia;
BOOL _ignoreNoticeMessages;
BOOL _ignorePrivateMessageHighlights;
BOOL _ignorePrivateMessages;
BOOL _ignorePublicMessageHighlights;
BOOL _ignorePublicMessages;
BOOL _trackUserActivity;
IRCAddressBookEntryType _entryType;
NSString *_hostmask;
NSString *_hostmaskRegularExpression;
NSString *_trackingNickname;
NSArray *_parentEntries;
@private
NSString *_uniqueIdentifier;
NSDictionary *_defaults;
}
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Internal/IRCChannelConfigInternal.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "IRCChannelConfigPrivate.h"
NS_ASSUME_NONNULL_BEGIN
@interface IRCChannelConfig ()
{
@protected
BOOL _autoJoin;
BOOL _ignoreGeneralEventMessages;
BOOL _ignoreHighlights;
BOOL _inlineMediaDisabled;
BOOL _inlineMediaEnabled;
BOOL _pushNotifications;
BOOL _showTreeBadgeCount;
IRCChannelType _type;
NSString *_channelName;
NSString *_label;
NSString *_defaultModes;
NSString *_defaultTopic;
NSString *_secretKey;
NSMutableDictionary *_notificationsMutable;
@private
NSString *_uniqueIdentifier;
NSDictionary *_defaults;
}
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Internal/IRCChannelUserInternal.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "IRCChannelUserPrivate.h"
NS_ASSUME_NONNULL_BEGIN
@interface IRCChannelUser ()
{
@protected
NSString *_modes;
double _incomingWeight;
double _outgoingWeight;
CFAbsoluteTime _lastWeightFade;
NSTimeInterval _creationTime;
}
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Internal/IRCClientConfigInternal.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "IRCClientConfigPrivate.h"
NS_ASSUME_NONNULL_BEGIN
@interface IRCClientConfig ()
{
@protected
BOOL _autoConnect;
BOOL _autoReconnect;
BOOL _autoSleepModeDisconnect;
BOOL _autojoinWaitsForNickServ;
BOOL _connectionPrefersIPv4;
BOOL _hideAutojoinDelayedWarnings;
BOOL _hideNetworkUnavailabilityNotices;
BOOL _performDisconnectOnPongTimer;
BOOL _performDisconnectOnReachabilityChange;
BOOL _performPongTimer;
BOOL _prefersSecuredConnection;
BOOL _saslAuthenticationDisableExternalMechanism;
BOOL _sendAuthenticationRequestsToUserServ;
BOOL _sendWhoCommandRequestsToChannels;
BOOL _setInvisibleModeOnConnect;
BOOL _sidebarItemExpanded;
BOOL _validateServerCertificateChain;
BOOL _zncIgnoreConfiguredAutojoin;
BOOL _zncIgnorePlaybackNotifications;
BOOL _zncIgnoreUserNotifications;
BOOL _zncOnlyPlaybackLatest;
IRCConnectionAddressType _addressType;
IRCConnectionProxyType _proxyType;
NSArray *_ignoreList;
NSArray *_channelList;
NSArray *_highlightList;
NSArray *_alternateNicknames;
NSArray *_loginCommands;
NSArray *_serverList;
NSData *_identityClientSideCertificate;
NSString *_awayNickname;
NSString *_connectionName;
NSString *_nickname;
NSString *_nicknamePassword;
NSString *_normalLeavingComment;
NSString *_proxyAddress;
NSString *_proxyPassword;
NSString *_proxyUsername;
NSString *_realName;
NSString *_serverAddress;
NSString *_sleepModeLeavingComment;
NSString *_username;
NSStringEncoding _fallbackEncoding;
NSStringEncoding _primaryEncoding;
NSTimeInterval _lastMessageServerTime;
NSUInteger _floodControlDelayTimerInterval;
NSUInteger _floodControlMaximumMessages;
uint16_t _proxyPort;
uint16_t _serverPort;
RCMCipherSuiteCollection _cipherSuites;
@private
BOOL _migratedServerPasswordPendingDestroy;
NSUInteger _dictionaryVersion;
NSString *_uniqueIdentifier;
NSDictionary *_defaults;
}
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Internal/IRCHighlightLogEntryInternal.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "IRCHighlightLogEntryPrivate.h"
NS_ASSUME_NONNULL_BEGIN
@interface IRCHighlightLogEntry ()
{
@protected
TVCLogLine *_lineLogged;
NSString *_clientId;
NSString *_channelId;
}
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Internal/IRCHighlightMatchConditionInternal.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "IRCHighlightMatchCondition.h"
NS_ASSUME_NONNULL_BEGIN
@interface IRCHighlightMatchCondition ()
{
@protected
BOOL _matchIsExcluded;
NSString *_matchChannelId;
NSString *_matchKeyword;
@private
NSString *_uniqueIdentifier;
}
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Internal/IRCMessageInternal.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "IRCMessagePrivate.h"
NS_ASSUME_NONNULL_BEGIN
@interface IRCMessage ()
{
@protected
BOOL _isHistoric;
BOOL _isEventOnlyMessage;
BOOL _isPrintOnlyMessage;
IRCPrefix *_sender;
NSArray *_params;
NSDate *_receivedAt;
NSDictionary *_messageTags;
NSString *_batchToken;
NSString *_command;
NSUInteger _commandNumeric;
IRCMessageBatchMessage *_parentBatchMessage;
}
@end
@interface IRCMessage (IRCMessageLineParser)
- (BOOL)parseLine:(NSString *)line forClient:(nullable IRCClient *)client;
- (void)parseExtensions:(NSString *)extensionInfo forClient:(nullable IRCClient *)client;
- (void)parseSender:(NSString *)senderInfo forClient:(nullable IRCClient *)client;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Internal/IRCModeInfoInternal.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "IRCModeInfo.h"
NS_ASSUME_NONNULL_BEGIN
@interface IRCModeInfo ()
{
@protected
BOOL _modeIsSet;
NSString *_modeSymbol;
NSString *_modeParameter;
}
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Internal/IRCPrefixInternal.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "IRCPrefix.h"
NS_ASSUME_NONNULL_BEGIN
@interface IRCPrefix ()
{
@protected
BOOL _isServer;
NSString *_nickname;
NSString *_username;
NSString *_address;
NSString *_hostmask;
}
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Internal/IRCServerInternal.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "IRCServerPrivate.h"
NS_ASSUME_NONNULL_BEGIN
@interface IRCServer ()
{
@protected
BOOL _prefersSecuredConnection;
NSString *_serverAddress;
NSString *_serverPassword;
uint16_t _serverPort;
@private
NSString *_uniqueIdentifier;
NSDictionary *_defaults;
}
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Internal/IRCUserInternal.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "IRCUserPrivate.h"
NS_ASSUME_NONNULL_BEGIN
@interface IRCUser ()
{
@protected
NSString *_nickname;
NSString *_username;
NSString *_address;
NSString *_realName;
BOOL _isAway;
BOOL _isIRCop;
}
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Internal/TDCChannelPropertiesSheetInternal.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "TDCChannelPropertiesSheetPrivate.h"
NS_ASSUME_NONNULL_BEGIN
@class IRCChannelConfigMutable;
@interface TDCChannelPropertiesSheet ()
@property (nonatomic, strong) IRCChannelConfigMutable *config;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Internal/TDCChannelSpotlightAppearanceInternal.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "TDCChannelSpotlightAppearancePrivate.h"
NS_ASSUME_NONNULL_BEGIN
@class TDCChannelSpotlightPanel;
@interface TDCChannelSpotlightAppearance ()
- (nullable instancetype)initWithWindow:(TDCChannelSpotlightPanel *)window;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Internal/TDCChannelSpotlightControllerInternal.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "TDCChannelSpotlightControllerPrivate.h"
NS_ASSUME_NONNULL_BEGIN
@class TDCChannelSpotlightAppearance, TDCChannelSpotlightSearchResult;
@interface TDCChannelSpotlightController ()
- (TDCChannelSpotlightAppearance *)userInterfaceObjects;
@property (readonly, copy) NSString *searchString;
@property (readonly) NSArray *searchResults;
@property (readonly) NSArray *searchResultsFiltered;
@property (readonly) NSUInteger searchResultsCount;
@property (readonly) NSInteger selectedSearchResult; // -1 = none selected
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Internal/TDCFileTransferDialogInternal.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "TDCFileTransferDialogPrivate.h"
NS_ASSUME_NONNULL_BEGIN
@interface TDCFileTransferDialog ()
@property (nonatomic, copy, readwrite, nullable) NSString *IPAddress;
- (void)updateClearButton;
- (void)updateMaintenanceTimer;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Internal/TVCLogLineInternal.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "TVCLogLinePrivate.h"
NS_ASSUME_NONNULL_BEGIN
@interface TVCLogLine ()
{
@protected
BOOL _isEncrypted;
BOOL _isFirstForDay;
BOOL _nicknameColorStyleOverride;
NSArray *_excludeKeywords;
NSArray *_highlightKeywords;
NSDictionary *_rendererAttributes;
NSDate *_receivedAt;
NSString *_command;
NSString *_messageBody;
NSString *_nickname;
NSString *_nicknameColorStyle;
TVCLogLineMemberType _memberType;
TVCLogLineType _lineType;
NSUInteger _sessionIdentifier;
@private
NSString *_uniqueIdentifier;
}
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/NSColorHelper.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2008 - 2010 Satoshi Nakagawa
* Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
NS_ASSUME_NONNULL_BEGIN
@interface NSColor (TXColorHelper)
@property (class, readonly, copy) NSArray *formatterColors;
@property (class, readonly) NSColor *formatterWhiteColor;
@property (class, readonly) NSColor *formatterBlackColor;
@property (class, readonly) NSColor *formatterNavyBlueColor;
@property (class, readonly) NSColor *formatterDarkGreenColor;
@property (class, readonly) NSColor *formatterRedColor;
@property (class, readonly) NSColor *formatterBrownColor;
@property (class, readonly) NSColor *formatterPurpleColor;
@property (class, readonly) NSColor *formatterOrangeColor;
@property (class, readonly) NSColor *formatterYellowColor;
@property (class, readonly) NSColor *formatterLimeGreenColor;
@property (class, readonly) NSColor *formatterTealColor;
@property (class, readonly) NSColor *formatterAquaCyanColor;
@property (class, readonly) NSColor *formatterLightBlueColor;
@property (class, readonly) NSColor *formatterFuchsiaPinkColor;
@property (class, readonly) NSColor *formatterNormalGrayColor;
@property (class, readonly) NSColor *formatterLightGrayColor;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/NSStringHelper.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2008 - 2010 Satoshi Nakagawa
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
NS_ASSUME_NONNULL_BEGIN
@class IRCClient;
TEXTUAL_EXTERN NSStringEncoding const TXDefaultPrimaryStringEncoding;
TEXTUAL_EXTERN NSStringEncoding const TXDefaultFallbackStringEncoding;
@interface NSString (TXStringHelper)
@property (readonly, copy) NSString *stringByAppendingIRCFormattingStop;
@property (readonly, copy, nullable) NSString *channelNameWithoutBang; // "#channel" -> "channel", "##channel" -> "#channel"
- (nullable NSString *)channelNameWithoutBangOn:(IRCClient *)client;
@property (readonly, copy, nullable) NSString *nicknameFromHostmask;
@property (readonly, copy, nullable) NSString *usernameFromHostmask;
@property (readonly, copy, nullable) NSString *addressFromHostmask;
- (nullable NSAttributedString *)attributedStringWithIRCFormatting:(NSFont *)preferredFont preferredFontColor:(nullable NSColor *)preferredFontColor;
- (nullable NSAttributedString *)attributedStringWithIRCFormatting:(NSFont *)preferredFont preferredFontColor:(nullable NSColor *)preferredFontColor honorFormattingPreference:(BOOL)formattingPreference;
@property (readonly, copy) NSString *stripIRCEffects;
@property (getter=isValidInternetAddress, readonly) BOOL validInternetAddress;
@property (getter=isValidInternetPort, readonly) BOOL validInternetPort;
@property (getter=isHostmask, readonly) BOOL hostmask;
@property (getter=isIPv4Address, readonly) BOOL IPv4Address;
@property (getter=isIPv6Address, readonly) BOOL IPv6Address;
@property (getter=isIPAddress, readonly) BOOL IPAddress;
- (BOOL)hostmaskComponents:(NSString * _Nullable * _Nullable)nickname
username:(NSString * _Nullable * _Nullable)username
address:(NSString * _Nullable * _Nullable)address;
- (BOOL)hostmaskComponents:(NSString * _Nullable * _Nullable)nickname
username:(NSString * _Nullable * _Nullable)username
address:(NSString * _Nullable * _Nullable)address
onClient:(nullable IRCClient *)client;
@property (getter=isHostmaskNickname, readonly) BOOL hostmaskNickname;
@property (getter=isHostmaskAddress, readonly) BOOL hostmaskAddress;
@property (getter=isHostmaskUsername, readonly) BOOL hostmaskUsername;
/* By handing a client to -isHostmask[*]On:, greater validity
is promised as configuration options from ISUPPORT (005) and
other contextual information can be accessed. */
- (BOOL)isHostmaskNicknameOn:(nullable IRCClient *)client;
- (BOOL)isHostmaskUsernameOn:(nullable IRCClient *)client;
- (BOOL)isHostmaskAddressOn:(nullable IRCClient *)client;
@property (getter=isChannelName, readonly) BOOL channelName;
- (BOOL)isChannelNameOn:(IRCClient *)client; // Client to parse CHANTYPES from
@property (readonly, copy, nullable) NSString *stringWithValidURIScheme;
- (NSArray *)base64EncodingWithLineLength:(NSUInteger)lineLength;
- (NSUInteger)colorComponentsOfCharacter:(UniChar)character
startingAt:(NSUInteger)rangeStart
foregroundColor:(id _Nullable * _Nullable)foregroundColor
backgroundColor:(id _Nullable * _Nullable)backgroundColor;
- (nullable NSString *)padNicknameWithCharacter:(UniChar)padCharacter maximumLength:(NSUInteger)maximumLength;
@property (readonly, copy, nullable) NSString *prettyLicenseKey;
@property (readonly, copy) NSString *encodedMessageTagString;
@property (readonly, copy) NSString *decodedMessageTagString;
@property (getter=isModeSymbol, readonly) BOOL modeSymbol;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/NSViewHelper.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
NS_ASSUME_NONNULL_BEGIN
@interface NSWindow (TXWindowHelper)
/* Reset size of window to accommodate -minSize */
- (void)changeFrameToMin; // display = YES; animate = NO
- (void)changeFrameToMinAndDisplay:(BOOL)display; // animate = NO
- (void)changeFrameToMinAndDisplay:(BOOL)display animate:(BOOL)animate;
/* Sets content view to nil, resets frame to fit view, then assigns new view. */
- (void)replaceContentView:(NSView *)withView;
@end
@interface NSView (TXViewHelper)
/* Self top, right, bottom, left will = superview with 0.0 constant. */
- (void)addConstraintsToSuperviewToHugEdges;
/* Superview width and height will = self with 0.0 constant. */
/* A priority of 550 is used to encourage hugging. */
- (void)addConstraintsToSuperviewToEqualDimensions;
/* Remove first subview (if one is present) and replaces it with subview. */
/* The new superview width and height will equal that of subview with a
priority of 550. The subview top, right, bottom, and left will equal
that of the superview with 0.0 constant. */
/* See -addConstraintsToSuperviewToHugEdges
-addConstraintsToSuperviewToEqualDimensions */
- (void)replaceFirstSubview:(NSView *)withView;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Private/ICLPayloadLocalPrivate.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "ICLPayload.h"
NS_ASSUME_NONNULL_BEGIN
@interface ICLPayload (ICLPayloadLocalPrivate)
@property (copy, readonly) NSDictionary *javaScriptObject;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Private/IRCAddressBookMatchCachePrivate.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
NS_ASSUME_NONNULL_BEGIN
@class IRCAddressBookEntry, IRCClient;
@interface IRCAddressBookMatchCache : NSObject
@property (readonly, weak) IRCClient *client;
- (instancetype)initWithClient:(IRCClient *)client;
/* If multiple address book entries exist for the same host,
then we return all of them combined into a single instance.
This object will have a blank hostmask and the entry type
IRCAddressBookEntryTypeMixed. */
- (nullable IRCAddressBookEntry *)findAddressBookEntryForHostmask:(NSString *)hostmask;
- (NSArray *)findIgnoresForHostmask:(NSString *)hostmask;
- (void)clearCachedMatches;
- (void)clearCachedMatchesForHostmask:(NSString *)hostmask;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Private/IRCAddressBookUserTrackingPrivate.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "IRCAddressBookUserTracking.h"
NS_ASSUME_NONNULL_BEGIN
@interface IRCAddressBookUserTrackingContainer ()
- (instancetype)initWithClient:(IRCClient *)client;
- (IRCAddressBookUserTrackingStatus)_statusOfUser:(NSString *)nickname;
- (void)addTrackedUser:(NSString *)nickname;
- (void)_addTrackedUser:(NSString *)nickname;
- (void)removeTrackedUser:(NSString *)nickname;
- (void)_removeTrackedUser:(NSString *)nickname;
- (void)clearTrackedUsers;
- (void)statusOfTrackedNickname:(NSString *)nickname changedTo:(IRCAddressBookUserTrackingStatus)newStatus;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Private/IRCChannelConfigPrivate.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "IRCChannelConfig.h"
NS_ASSUME_NONNULL_BEGIN
@interface IRCChannelConfig ()
@property (readonly, copy) NSDictionary *notifications;
- (void)writeSecretKeyToKeychain;
- (void)destroySecretKeyKeychainItem;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Private/IRCChannelMemberListControllerPrivate.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
NS_ASSUME_NONNULL_BEGIN
@class IRCChannel;
/* The member list controller is the controller bound to the view in the
main window. IRCChannelMemberList, when assigned to it, will maintain a
1:1 relation to its internal list and the content of the controller. */
/* DO NOT modify the controller directly. Allow IRCChannelMemberList to
do the work for you to maintain the integrity of the internal list and
the content of the controller. */
@interface IRCChannelMemberListController : NSArrayController
/* A controller can be assigned to only one channel or none. */
/* TVCMainWindow is responsible for assignment using TVCMemberList
as a proxy. */
- (void)assignToChannel:(nullable IRCChannel *)channel;
- (void)replaceContents:(NSArray *)contents;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Private/IRCChannelMemberListPrivate.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "IRCChannelMemberList.h"
NS_ASSUME_NONNULL_BEGIN
@class IRCChannel, IRCChannelMemberListController;
@protocol IRCChannelMemberListPrivatePrototype
- (void)addMember:(IRCChannelUser *)member checkForDuplicates:(BOOL)checkForDuplicates;
/* The replaceInAllChannels: flag should only be used in extreme cases because there is A LOT
of overhead to setting it. Textual only does it when the user list is configured to sort IRCop
at top and IRCop status changes. That change requires the user to be resorted in every channel
they are in. Knowing which channels they are in is easy because of IRCUserRelations, but the
actual process of finding where to sort them at is very expensive. */
- (void)replaceMember:(IRCChannelUser *)member1 withMember:(IRCChannelUser *)member2;
- (void)replaceMember:(IRCChannelUser *)member1 withMember:(IRCChannelUser *)member2 resort:(BOOL)resort;
- (void)replaceMember:(IRCChannelUser *)member1 withMember:(IRCChannelUser *)member2 resort:(BOOL)resort replaceInAllChannels:(BOOL)replaceInAllChannels;
- (void)changeMember:(NSString *)nickname mode:(NSString *)mode value:(BOOL)value;
- (void)resortMember:(IRCChannelUser *)member;
- (void)clearMembers;
- (NSData *)pasteboardDataForMembers:(NSArray *)members;
+ (BOOL)readNicknamesFromPasteboardData:(NSData *)pasteboardData withBlock:(void (NS_NOESCAPE ^)(IRCChannel *channel, NSArray *nicknames))callbackBlock;
+ (BOOL)readMembersFromPasteboardData:(NSData *)pasteboardData withBlock:(void (NS_NOESCAPE ^)(IRCChannel *channel, NSArray *members))callbackBlock;
@end
@interface IRCChannelMemberList ()
- (instancetype)initWithChannel:(IRCChannel *)channel NS_DESIGNATED_INITIALIZER;
+ (void)suspendMemberListSerialQueues;
+ (void)resumeMemberListSerialQueues;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Private/IRCChannelModePrivate.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "IRCChannelMode.h"
NS_ASSUME_NONNULL_BEGIN
@class IRCChannel;
@interface IRCChannelMode ()
- (instancetype)initWithChannel:(IRCChannel *)channel NS_DESIGNATED_INITIALIZER;
- (NSArray *)updateModes:(NSString *)modeString;
- (void)clear;
@end
#pragma mark -
@interface IRCChannelModeContainer ()
- (void)applyModes:(NSArray *)modes;
- (void)clear;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Private/IRCChannelPrivate.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "IRCChannel.h"
#import "IRCChannelMemberListPrivate.h"
#import "TVCLogController.h"
NS_ASSUME_NONNULL_BEGIN
@class TVCLogLine;
@interface IRCChannel ()
@property (nonatomic, assign, readwrite) IRCChannelStatus status;
@property (nonatomic, assign) BOOL sentInitialWhoRequest;
@property (nonatomic, assign) BOOL channelModesReceived;
@property (nonatomic, assign) BOOL channelNamesReceived;
@property (nonatomic, assign, readwrite) BOOL errorOnLastJoinAttempt;
- (instancetype)initWithConfig:(IRCChannelConfig *)config NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithConfigDictionary:(NSDictionary *)dic;
- (void)updateConfig:(IRCChannelConfig *)config;
- (void)updateConfig:(IRCChannelConfig *)config fireChangedNotification:(BOOL)fireChangedNotification;
- (void)updateConfig:(IRCChannelConfig *)config fireChangedNotification:(BOOL)fireChangedNotification updateStoredChannelList:(BOOL)updateStoredChannelList;
- (NSDictionary *)configurationDictionary;
#if TEXTUAL_BUILT_WITH_ADVANCED_ENCRYPTION == 1
- (void)noteEncryptionStateDidChange;
#endif
- (void)writeToLogLineToLogFile:(TVCLogLine *)logLine;
- (void)logFileWriteSessionBegin;
- (void)logFileWriteSessionEnd;
- (void)print:(TVCLogLine *)logLine;
- (void)print:(TVCLogLine *)logLine completionBlock:(nullable TVCLogControllerPrintOperationCompletionBlock)completionBlock;
- (void)reopenLogFileIfNeeded;
- (void)closeLogFile;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Private/IRCChannelUserPrivate.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "IRCChannelUser.h"
NS_ASSUME_NONNULL_BEGIN
@interface IRCChannelUser ()
- (instancetype)initWithUser:(IRCUser *)user;
- (void)changeUserToUser:(IRCUser *)user;
- (void)conversation;
- (void)incomingConversation;
- (void)outgoingConversation;
+ (NSComparator)channelRankComparator;
+ (NSComparator)nicknameLengthComparator;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Private/IRCClientConfigPrivate.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "IRCClientConfig.h"
NS_ASSUME_NONNULL_BEGIN
@interface IRCClientConfig ()
/* To provide user with similar behavior, when migrating -connectionPrefersIPv4
in IRCClientConfig, we set the address type to IRCConnectionAddressTypeIPv4.
We check if both values are set to offer the user a warning that the preference
they had has changed in a way they may not want. When user changes the address
type in Server Properties, we unset -connectionPrefersIPv4 so that the warning
does not appear again, ever. */
@property (readonly) BOOL showConnectionPrefersIPv4Warning;
@property (readonly) BOOL connectionPrefersIPv4 TEXTUAL_DEPRECATED("Use -addressType instead");
- (void)writeNicknamePasswordToKeychain;
- (void)writeProxyPasswordToKeychain;
- (void)destroyNicknamePasswordKeychainItem;
- (void)destroyProxyPasswordKeychainItem;
- (void)destroyServerPasswordKeychainItemAfterMigration;
@end
@interface IRCClientConfigMutable ()
@property (nonatomic, assign, readwrite) BOOL connectionPrefersIPv4 TEXTUAL_DEPRECATED("Use -addressType instead");
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Private/IRCClientPrivate.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "TLONotificationController.h"
#import "IRCClient.h"
NS_ASSUME_NONNULL_BEGIN
@class TLOSpokenNotification;
@class IRCAddressBookUserTrackingContainer, IRCTimedCommand, IRCUserMutable;
enum {
ClientIRCv3SupportedCapabilitySASLGeneric = 1 << 22,
ClientIRCv3SupportedCapabilitySASLPlainText = 1 << 23, // YES if SASL=plain CAP is supported
ClientIRCv3SupportedCapabilitySASLExternal = 1 << 24, // YES if SASL=external CAP is supported
ClientIRCv3SupportedCapabilityZNCServerTime = 1 << 25, // YES if the ZNC vendor specific CAP supported
ClientIRCv3SupportedCapabilityZNCServerTimeISO = 1 << 26, // YES if the ZNC vendor specific CAP supported
ClientIRCv3SupportedCapabilityZNCPlaybackModule = 1 << 27, // YES if the ZNC vendor specific CAP supported
ClientIRCv3SupportedCapabilityPlanioPlayback = 1 << 28 // YES if the plan.io vendor specific CAP supported.
};
@interface IRCClient ()
@property (nonatomic, copy, nullable) dispatch_block_t disconnectCallback;
@property (nonatomic, assign, readwrite) IRCClientConnectMode connectType;
@property (nonatomic, assign, readwrite) IRCClientDisconnectMode disconnectType;
@property (nonatomic, assign) BOOL sidebarItemIsExpanded;
@property (nonatomic, copy, readwrite) NSArray *channelList;
@property (nonatomic, weak, readwrite) IRCChannel *lastSelectedChannel;
- (instancetype)initWithConfig:(IRCClientConfig *)config NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithConfigDictionary:(NSDictionary *)dic;
- (void)updateConfig:(IRCClientConfig *)config;
- (void)updateConfig:(IRCClientConfig *)config updateSelection:(BOOL)updateSelection;
- (NSDictionary *)configurationDictionary;
- (void)addChannel:(IRCChannel *)channel;
- (void)addChannel:(IRCChannel *)channel atPosition:(NSUInteger)position;
- (void)removeChannel:(IRCChannel *)channel; // This only removes the channel from channel array. Use world controller to properly destroy a channel.
- (NSUInteger)indexOfChannel:(IRCChannel *)channel;
- (void)selectFirstChannelInChannelList;
- (void)reloadServerListItems;
- (void)updateStoredChannelList;
- (void)cacheHighlightInChannel:(IRCChannel *)channel withLogLine:(TVCLogLine *)logLine;
- (void)inputText:(id)string destination:(IRCTreeItem *)destination;
- (void)inputText:(id)string asCommand:(IRCRemoteCommand)command;
- (void)inputText:(id)string asCommand:(IRCRemoteCommand)command destination:(IRCTreeItem *)destination;
- (void)enableCapability:(ClientIRCv3SupportedCapability)capability;
- (void)disableCapability:(ClientIRCv3SupportedCapability)capability;
- (void)noteReachabilityChanged:(BOOL)reachable;
- (void)autoConnectWithDelay:(NSUInteger)delay afterWakeUp:(BOOL)afterWakeUp;
- (void)postEventToViewController:(NSString *)eventToken;
- (void)postEventToViewController:(NSString *)eventToken forChannel:(IRCChannel *)channel;
- (void)sendFile:(NSString *)nickname port:(uint16_t)port filename:(NSString *)filename filesize:(uint64_t)totalFilesize token:(nullable NSString *)transferToken;
- (void)sendFileResume:(NSString *)nickname port:(uint16_t)port filename:(NSString *)filename filesize:(uint64_t)totalFilesize token:(nullable NSString *)transferToken;
- (void)sendFileResumeAccept:(NSString *)nickname port:(uint16_t)port filename:(NSString *)filename filesize:(uint64_t)totalFilesize token:(nullable NSString *)transferToken;
- (void)notifyFileTransfer:(TXNotificationType)type nickname:(NSString *)nickname filename:(NSString *)filename filesize:(uint64_t)totalFilesize requestIdentifier:(NSString *)identifier;
- (IRCAddressBookUserTrackingContainer *)trackedUsers;
- (IRCUserMutable *)mutableCopyOfUserWithNickname:(NSString *)nickname;
- (void)modifyUser:(IRCUser *)user withBlock:(void (NS_NOESCAPE ^)(IRCUserMutable *userMutable))block;
- (void)modifyUserUserWithNickname:(NSString *)nickname withBlock:(void (NS_NOESCAPE ^)(IRCUserMutable *userMutable))block;
- (void)reopenLogFileIfNeeded;
- (void)closeLogFile;
- (nullable IRCChannel *)findChannelOrCreate:(NSString *)withName isUtility:(BOOL)isUtility;
- (nullable NSString *)formatNotificationToSpeak:(TLOSpokenNotification *)notification;
- (id)queuedBatchMessageWithToken:(NSString *)batchToken;
- (void)print:(NSString *)messageBody by:(nullable NSString *)nickname inChannel:(nullable IRCChannel *)channel asType:(TVCLogLineType)lineType command:(NSString *)command escapeMessage:(BOOL)escapeMessage;
- (void)onTimedCommand:(IRCTimedCommand *)timedCommand;
- (void)logFileRecordSessionChanged:(BOOL)toNewSession inChannel:(nullable IRCChannel *)channel;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Private/IRCClientRequestedCommandsPrivate.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "IRCCommandIndex.h"
NS_ASSUME_NONNULL_BEGIN
/* The response of some commands are shown and hidden depending
on who sent the command. IRCClientRequestedCommands is used by
IRCClient internally to keep track of what commands have been
requested so that it can determine how to treat the response. */
/* IRCClientRequestedCommands works in conjunction with IRCClient
by balancing all calls to a command. */
@interface IRCClientRequestedCommands : NSObject
- (void)removeCommands;
@end
#pragma mark -
@interface IRCClientRequestedCommands (Helpers)
#pragma mark -
#pragma mark ISON Command (Default: hidden)
@property (readonly, getter=inVisibleIsonRequest) BOOL visibleIsonRequest;
- (void)recordIsonRequestOpened;
- (void)recordIsonRequestOpenedAsVisible;
- (void)recordIsonRequestClosed;
#pragma mark -
#pragma mark MONITOR Command (Default: hidden)
#if 0
/* The MONITOR command can perform multiple actions which means its results
do not always have a predetermined number of results or an end numeric. */
/* To work around this, we feed IRCClientRequestedCommands an estimate
of the number of responses to expect. We then decrement that by calling
the *ClosedOne for each response received. When the count reaches zero,
the request is automatically closed without calling *Closed. */
/* If we encounter an error, we instead call *Closed which ends the request there. */
@property (readonly, getter=inVisibleMonitorRequest) BOOL visibleMonitorRequest;
- (void)recordMonitorRequestOpened; // No limit on count
- (void)recordMonitorRequestOpenedWithCount:(NSUInteger)count;
- (void)recordMonitorRequestOpenedAsVisible; // No limit on count
- (void)recordMonitorRequestOpenedAsVisibleWithCount:(NSUInteger)count;
- (void)recordMonitorRequestClosedOne; // Does nothing if no count is specified
- (void)recordMonitorRequestClosed;
#pragma mark -
#pragma mark NAMES Command (Default: hidden)
@property (readonly, getter=inVisibleNamesRequest) BOOL visibleNamesRequest;
- (void)recordNamesRequestOpened;
- (void)recordNamesRequestOpenedAsVisible;
- (void)recordNamesRequestClosed;
#pragma mark -
#pragma mark WATCH Command (Default: hidden)
@property (readonly, getter=inVisibleWatchRequest) BOOL visibleWatchRequest;
- (void)recordWatchRequestOpened; // No limit on count
- (void)recordWatchRequestOpenedWithCount:(NSUInteger)count;
- (void)recordWatchRequestOpenedAsVisible; // No limit on count
- (void)recordWatchRequestOpenedAsVisibleWithCount:(NSUInteger)count;
- (void)recordWatchRequestClosedOne; // Does nothing if no count is specified
- (void)recordWatchRequestClosed;
#endif
#pragma mark -
#pragma mark WHO Command (Default: hidden)
@property (readonly, getter=inVisibleWhoRequest) BOOL visibleWhoRequest;
- (void)recordWhoRequestOpened;
- (void)recordWhoRequestOpenedAsVisible;
- (void)recordWhoRequestClosed;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Private/IRCColorFormatPrivate.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "TVCLogLine.h"
#import "IRCColorFormat.h"
NS_ASSUME_NONNULL_BEGIN
@class IRCClient, IRCChannel;
@interface NSAttributedString (IRCTextFormatterPrivate)
/* Given contextual information (client, channel, lineType), the original
attributed string is converted to use appropriate formatting characters,
but this method does not allow the result to exceed TXMaximumIRCBodyLength. */
/* The only valid lineType value is PRIVMSG, ACTION, or NOTICE. */
/* effectiveRange is the range of the result in the attributed string.
Use this value to delete those characters during enumeration. */
- (NSString *)stringFormattedForChannel:(NSString *)channelName
onClient:(IRCClient *)client
withLineType:(TVCLogLineType)lineType
effectiveRange:(NSRange * _Nullable)effectiveRange;
@end
@interface NSMutableAttributedString (IRCTextFormatterPrivate)
/* This method truncates self to the effective range */
- (NSString *)stringFormattedForChannel:(NSString *)channelName
onClient:(IRCClient *)client
withLineType:(TVCLogLineType)lineType;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Private/IRCCommandIndexPrivate.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "IRCCommandIndex.h"
NS_ASSUME_NONNULL_BEGIN
@interface IRCCommandIndex ()
+ (void)populateCommandIndex;
+ (void)invalidateCaches;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Private/IRCConnectionPrivate.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2008 - 2010 Satoshi Nakagawa
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "IRCConnection.h"
NS_ASSUME_NONNULL_BEGIN
@interface IRCConnection ()
@property (nonatomic, copy, readwrite) IRCConnectionConfig *config;
@property (nonatomic, assign, readwrite) BOOL isConnected;
@property (nonatomic, assign, readwrite) BOOL isConnecting;
@property (nonatomic, assign, readwrite) BOOL isDisconnecting;
@property (nonatomic, assign, readwrite) BOOL isSending;
@property (nonatomic, assign, readwrite) BOOL isSecured;
@property (nonatomic, assign, readwrite) BOOL isConnectedWithClientSideCertificate;
@property (nonatomic, assign, readwrite) BOOL EOFReceived;
@property (nonatomic, copy, readwrite, nullable) NSString *connectedAddress;
- (void)enforceFloodControl;
- (void)openSecuredConnectionCertificateModal;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Private/IRCExtrasPrivate.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2008 - 2010 Satoshi Nakagawa
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
NS_ASSUME_NONNULL_BEGIN
@interface IRCExtras : NSObject
+ (void)parseIRCProtocolURI:(NSString *)location;
+ (void)parseIRCProtocolURI:(NSString *)location
withDescriptor:(nullable NSAppleEventDescriptor *)event;
+ (void)createConnectionToServer:(NSString *)serverInfo
channelList:(nullable NSString *)channelList
connectWhenCreated:(BOOL)connectWhenCreated;
+ (void)createConnectionToServer:(NSString *)serverInfo
channelList:(nullable NSString *)channelList
connectWhenCreated:(BOOL)connectWhenCreated
mergeConnectionIfPossible:(BOOL)mergeConnectionIfPossible
selectFirstChannelAdded:(BOOL)selectFirstChannelAdded;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Private/IRCHighlightLogEntryPrivate.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "IRCHighlightLogEntry.h"
NS_ASSUME_NONNULL_BEGIN
@class IRCChannel;
@interface IRCHighlightLogEntry ()
@property (readonly, weak) IRCChannel *channel;
@property (readonly, copy) NSString *channelName;
@property (readonly, copy) NSString *timeLoggedFormatted;
@end
@interface IRCHighlightLogEntryMutable : IRCHighlightLogEntry
@property (nonatomic, copy, readwrite) TVCLogLine *lineLogged;
@property (nonatomic, copy, readwrite) NSString *clientId;
@property (nonatomic, copy, readwrite) NSString *channelId;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Private/IRCISupportInfoPrivate.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "IRCISupportInfo.h"
NS_ASSUME_NONNULL_BEGIN
@class IRCClient;
@interface IRCISupportInfo ()
@property (nonatomic, copy, readwrite, nullable) NSString *serverAddress;
@property (readonly, copy, nullable) NSString *stringValueForLastUpdate;
- (instancetype)initWithClient:(IRCClient *)client NS_DESIGNATED_INITIALIZER;
- (void)processConfigurationData:(NSString *)configurationData;
- (NSArray *)parseModes:(NSString *)modeString;
- (void)reset;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Private/IRCMessageBatchPrivate.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
NS_ASSUME_NONNULL_BEGIN
/* Each IRCClient is assigned a single instance of
IRCMessageBatchMessageContainer which acts as a container for
all BATCH command events that the client may receive. */
@interface IRCMessageBatchMessageContainer : NSObject
@property (readonly, copy) NSDictionary *queuedEntries;
- (void)queueEntry:(id)entry;
- (void)dequeueEntry:(id)entry;
- (void)dequeueEntries;
- (id)queuedEntryWithBatchToken:(NSString *)batchToken;
@end
/* IRCMessageBatchMessage represents a single BATCH event based
on its token value. Queued entries can either be an IRCMessage
instance or IRCMessageBatchMessage (for nested batch events). */
@interface IRCMessageBatchMessage : NSObject
@property (nonatomic, assign) BOOL batchIsOpen;
@property (nonatomic, copy) NSString *batchToken;
@property (nonatomic, copy, nullable) NSString *batchType;
@property (readonly, copy) NSArray *queuedEntries;
@property (nonatomic, weak) IRCMessageBatchMessage *parentBatchMessage;
- (void)queueEntry:(id)entry;
- (void)dequeueEntry:(id)entry;
- (void)dequeueEntries;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Private/IRCMessagePrivate.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "IRCMessage.h"
NS_ASSUME_NONNULL_BEGIN
@class IRCMessageBatchMessage;
@interface IRCMessage ()
@property (readonly, strong, nullable) IRCMessageBatchMessage *parentBatchMessage;
- (void)markAsNotHistoric;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Private/IRCServerPrivate.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "IRCServer.h"
NS_ASSUME_NONNULL_BEGIN
@interface IRCServer ()
/* IRCClient retains a copy of the active IRCServer instance.
When the -serverList in IRCClientConfig is modified,
any servers that are removed will have their keychain
items destroyed. We do not want to destroy the keychain
items for the IRCServer instance that IRCClient has a copy
of, so the -destroyKeychainItemsDuringDealloc flag is used.
This tells the IRCServer instance to hold onto the keychain
item until there is no longer a reference to it. */
@property (nonatomic, assign) BOOL destroyKeychainItemsDuringDealloc;
- (void)writeServerPasswordToKeychain;
- (void)destroyServerPasswordKeychainItem;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Private/IRCTimerCommandPrivate.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2008 - 2010 Satoshi Nakagawa
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
NS_ASSUME_NONNULL_BEGIN
@class IRCClient, IRCChannel;
@interface IRCTimedCommand : NSObject
@property (readonly, copy) NSString *identifier;
@property (readonly, copy) NSString *clientId;
@property (readonly, copy, nullable) NSString *channelId;
@property (readonly, copy) NSString *command;
@property (readonly) NSTimeInterval startTime;
@property (readonly) NSTimeInterval timeRemaining;
@property (readonly) NSTimeInterval timerInterval;
@property (readonly) BOOL timerIsActive;
@property (readonly) BOOL repeatTimer;
@property (readonly) NSUInteger iterations;
@property (readonly) NSUInteger currentIteration;
- (instancetype)init NS_UNAVAILABLE;
- (instancetype)initWithCommand:(NSString *)command onClient:(IRCClient *)client;
- (instancetype)initWithCommand:(NSString *)command onClient:(IRCClient *)client inChannel:(nullable IRCChannel *)channel NS_DESIGNATED_INITIALIZER;
- (void)start:(NSTimeInterval)interval; // repeatTimer = NO
- (void)start:(NSTimeInterval)timerInterval onRepeat:(BOOL)repeatTimer; // iterations = 0
- (void)start:(NSTimeInterval)timerInterval onRepeat:(BOOL)repeatTimer iterations:(NSUInteger)iterations; // 0 iterations = infinite
- (void)stop;
/* If the timer has been started before, then
we already know the values to pass to -start:
In that case, we return YES.
If we don't know this information yet, then
we return NO. */
/* Restarting the timer resets the iteration count. */
- (BOOL)restart;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Private/IRCTreeItemPrivate.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "IRCTreeItem.h"
NS_ASSUME_NONNULL_BEGIN
@interface IRCTreeItem ()
@property (nonatomic, assign, readwrite) NSUInteger dockUnreadCount;
@property (nonatomic, assign, readwrite) NSUInteger nicknameHighlightCount;
@property (nonatomic, assign, readwrite) NSUInteger treeUnreadCount;
@property (nonatomic, weak, readwrite) IRCClient *associatedClient;
@property (nonatomic, strong, readwrite) TVCLogController *viewController;
- (void)resetState;
@property (readonly) NSUInteger numberOfChildren;
- (nullable IRCTreeItem *)childAtIndex:(NSUInteger)index;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Private/IRCUserNicknameColorStyleGeneratorPrivate.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "TPCTheme.h"
NS_ASSUME_NONNULL_BEGIN
@interface IRCUserNicknameColorStyleGenerator : NSObject
+ (NSString *)nicknameColorStyleForString:(NSString *)inputString;
+ (NSString *)nicknameColorStyleForString:(NSString *)inputString isOverride:(BOOL * _Nullable)isOverride;
+ (NSNumber *)hashForString:(NSString *)inputString colorStyle:(TPCThemeSettingsNicknameColorStyle)colorStyle;
+ (nullable NSColor *)nicknameColorStyleOverrideForKey:(NSString *)styleKey;
+ (void)setNicknameColorStyleOverride:(nullable NSColor *)styleValue forKey:(NSString *)styleKey;
+ (void)migrateNicknameColorStyleOverrides;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Private/IRCUserPersistentStorePrivate.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
NS_ASSUME_NONNULL_BEGIN
/* IRCUserPersistentStore is a class used by IRCUser to store
properties which are persistent between multiple read-only
and mutable copies of the same IRCUser instance. */
@class IRCUserRelations;
@interface IRCUserPersistentStore : NSObject
@property (nonatomic, strong) IRCUserRelations *relations;
@property (nonatomic, assign) CFAbsoluteTime presentAwayMessageFor301LastEvent;
@property (nonatomic, strong) dispatch_source_t removeUserTimer;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Private/IRCUserPrivate.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "IRCUser.h"
NS_ASSUME_NONNULL_BEGIN
@interface IRCUser ()
- (IRCClient *)client;
- (void)cancelRemoveUserTimer;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Private/IRCUserRelationsPrivate.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "IRCChannelUser.h"
#import "IRCUserRelations.h"
NS_ASSUME_NONNULL_BEGIN
/* IRCUserRelations is a class used by IRCUser to store which
IRCChannelUser object is associated with a particular channel. */
@interface IRCUserRelations : NSObject
@property (readonly, copy) NSArray *relatedChannels;
@property (readonly, copy) NSArray *relatedUsers;
@property (readonly, copy) NSDictionary *relations;
@property (readonly) NSUInteger numberOfRelations;
- (void)associateUser:(IRCChannelUser *)user withChannel:(IRCChannel *)channel;
- (void)disassociateUserWithChannel:(IRCChannel *)channel;
- (nullable IRCChannelUser *)userAssociatedWithChannel:(IRCChannel *)channel;
- (void)enumerateRelations:(void (NS_NOESCAPE ^)(IRCChannel *channel, IRCChannelUser *member, BOOL *stop))block;
@end
#pragma mark -
/* Acts as easy access for internal relations object */
@interface IRCUser (IRCUserRelationsPrivate)
- (void)becamePrimaryUser;
- (void)associateUser:(IRCChannelUser *)user withChannel:(IRCChannel *)channel;
- (void)disassociateUserWithChannel:(IRCChannel *)channel;
- (nullable IRCChannelUser *)userAssociatedWithChannel:(IRCChannel *)channel;
- (void)enumerateRelations:(void (NS_NOESCAPE ^)(IRCChannel *channel, IRCChannelUser *member, BOOL *stop))block;
@end
@interface IRCChannelUser (IRCUserRelationsPrivate)
- (void)associateWithChannel:(IRCChannel *)channel;
- (void)disassociateWithChannel:(IRCChannel *)channel;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Private/IRCWorldPrivate.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "IRCChannelConfigPrivate.h"
#import "IRCWorld.h"
NS_ASSUME_NONNULL_BEGIN
@interface IRCWorld ()
@property (nonatomic, assign, readwrite) NSUInteger messagesSent;
@property (nonatomic, assign, readwrite) NSUInteger messagesReceived;
@property (nonatomic, assign, readwrite) uint64_t bandwidthIn;
@property (nonatomic, assign, readwrite) uint64_t bandwidthOut;
@property (nonatomic, assign) BOOL isImportingConfiguration;
@property (nonatomic, copy, readwrite) NSArray *clientList;
- (void)setupConfiguration;
- (nullable IRCTreeItem *)findItemWithPasteboardString:(NSString *)string;
- (NSString *)pasteboardStringForItem:(IRCTreeItem *)item;
- (void)autoConnectAfterWakeup:(BOOL)afterWakeUp;
- (void)prepareForSleep;
- (void)prepareForScreenSleep;
- (void)wakeFromScreenSleep;
- (void)noteReachabilityChanged:(BOOL)reachable;
- (IRCClient *)createClientWithConfig:(IRCClientConfig *)config reload:(BOOL)reload;
- (IRCChannel *)createChannelWithConfig:(IRCChannelConfig *)config onClient:(IRCClient *)client add:(BOOL)add adjust:(BOOL)adjust reload:(BOOL)reload;
- (IRCChannel *)createPrivateMessage:(NSString *)nickname onClient:(IRCClient *)client asType:(IRCChannelType)type;
- (void)destroyClient:(IRCClient *)client;
- (void)destroyChannel:(IRCChannel *)channel reload:(BOOL)reload;
- (void)destroyChannel:(IRCChannel *)channel reload:(BOOL)reload part:(BOOL)partChannel;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Private/NSTableVIewHelperPrivate.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
NS_ASSUME_NONNULL_BEGIN
@interface NSTableView (TXTableViewHelper)
+ (NSFont *)preferredGlobalTableViewFont;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Private/NSViewHelperPrivate.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
NS_ASSUME_NONNULL_BEGIN
@class TVCMainWindow;
@interface NSView (TXViewHelperPrivate)
/* If this view is attached to an instance of TXMainWindow,
then this returns the instance its attached to. */
@property (readonly, nullable) TVCMainWindow *mainWindow;
@end
@interface NSCell (TXCellHelperPrivate)
@property (readonly, nullable) NSWindow *window;
@property (readonly, nullable) TVCMainWindow *mainWindow;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Private/SwiftBridgingHeaderPrivate.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "TextualPrivate.h"
// TLOpenLink.swift
#import "TPCPreferencesLocal.h"
// TLOLinkParser.swift
#import "TVCLogLine.h"
================================================
FILE: Sources/App/Classes/Headers/Private/TDCAboutDialogPrivate.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "TDCWindowBase.h"
NS_ASSUME_NONNULL_BEGIN
@protocol TDCAboutDialogDelegate;
@interface TDCAboutDialog : TDCWindowBase
@end
@protocol TDCAboutDialogDelegate
@required
- (void)aboutDialogWillClose:(TDCAboutDialog *)sender;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Private/TDCAddressBookSheetPrivate.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2008 - 2010 Satoshi Nakagawa
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "IRCAddressBook.h"
#import "TDCSheetBase.h"
NS_ASSUME_NONNULL_BEGIN
@protocol TDCAddressBookSheetDelegate;
@interface TDCAddressBookSheet : TDCSheetBase
- (instancetype)initWithEntryType:(IRCAddressBookEntryType)entryType NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithConfig:(IRCAddressBookEntry *)config NS_DESIGNATED_INITIALIZER;
- (void)start;
@end
@protocol TDCAddressBookSheetDelegate
@required
- (void)addressBookSheet:(TDCAddressBookSheet *)sender onOk:(IRCAddressBookEntry *)config;
- (void)addressBookSheetWillClose:(TDCAddressBookSheet *)sender;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Private/TDCChannelBanListSheetPrivate.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "IRCISupportInfo.h"
#import "TDCSharedProtocolDefinitionsPrivate.h"
#import "TDCSheetBase.h"
NS_ASSUME_NONNULL_BEGIN
@class IRCChannel;
typedef NS_ENUM(NSUInteger, TDCChannelBanListSheetEntryType) {
TDCChannelBanListSheetEntryTypeBan = IRCISupportInfoListTypeBan,
TDCChannelBanListSheetEntryTypeBanException = IRCISupportInfoListTypeBanException,
TDCChannelBanListSheetEntryTypeInviteException = IRCISupportInfoListTypeInviteException,
TDCChannelBanListSheetEntryTypeQuiet = IRCISupportInfoListTypeQuiet
};
@interface TDCChannelBanListSheet : TDCSheetBase
@property (readonly) TDCChannelBanListSheetEntryType entryType;
@property (readonly, copy) NSString *modeSymbol;
@property (readonly, copy, nullable) NSArray *listOfChanges;
@property (nonatomic, assign) BOOL contentAlreadyReceived;
/* Returns nil if entry type is not supported by client */
- (nullable instancetype)initWithEntryType:(TDCChannelBanListSheetEntryType)entryType inChannel:(IRCChannel *)channel NS_DESIGNATED_INITIALIZER;
- (void)start;
- (void)clear;
- (void)addEntry:(NSString *)entryMask setBy:(nullable NSString *)entryAuthor creationDate:(nullable NSDate *)entryCreationDate;
@end
@protocol TDCChannelBanListSheetDelegate
@required
- (void)channelBanListSheetOnUpdate:(TDCChannelBanListSheet *)sender;
- (void)channelBanListSheetWillClose:(TDCChannelBanListSheet *)sender;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Private/TDCChannelInviteSheetPrivate.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2008 - 2010 Satoshi Nakagawa
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "TDCSharedProtocolDefinitionsPrivate.h"
#import "TDCSheetBase.h"
NS_ASSUME_NONNULL_BEGIN
@class IRCClient;
@interface TDCChannelInviteSheet : TDCSheetBase
@property (readonly, copy) NSArray *nicknames;
- (instancetype)initWithNicknames:(NSArray *)nicknames onClient:(IRCClient *)client NS_DESIGNATED_INITIALIZER;
- (void)startWithChannels:(NSArray *)channels;
@end
@protocol TDCChannelInviteSheetDelegate
@required
- (void)channelInviteSheet:(TDCChannelInviteSheet *)sender onSelectChannel:(NSString *)channelName;
- (void)channelInviteSheetWillClose:(TDCChannelInviteSheet *)sender;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Private/TDCChannelModifyModesSheetPrivate.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2008 - 2010 Satoshi Nakagawa
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "TDCSharedProtocolDefinitionsPrivate.h"
#import "TDCSheetBase.h"
NS_ASSUME_NONNULL_BEGIN
@class IRCChannel, IRCChannelModeContainer;
@interface TDCChannelModifyModesSheet : TDCSheetBase
- (instancetype)initWithChannel:(IRCChannel *)channel NS_DESIGNATED_INITIALIZER;
- (void)start;
@end
@protocol TDCChannelModifyModesSheetDelegate
@required
- (void)channelModifyModesSheet:(TDCChannelModifyModesSheet *)sender onOk:(IRCChannelModeContainer *)modes;
- (void)channelModifyModesSheetWillClose:(TDCChannelModifyModesSheet *)sender;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Private/TDCChannelModifyTopicSheetPrivate.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2008 - 2010 Satoshi Nakagawa
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "TDCSharedProtocolDefinitionsPrivate.h"
#import "TDCSheetBase.h"
NS_ASSUME_NONNULL_BEGIN
@class IRCChannel;
@interface TDCChannelModifyTopicSheet : TDCSheetBase
- (instancetype)initWithChannel:(IRCChannel *)channel NS_DESIGNATED_INITIALIZER;
- (void)start;
@end
@protocol TDCChannelModifyTopicSheetDelegate
@required
- (void)channelModifyTopicSheet:(TDCChannelModifyTopicSheet *)sender onOk:(NSString *)topic;
- (void)channelModifyTopicSheetWillClose:(TDCChannelModifyTopicSheet *)sender;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Private/TDCChannelPropertiesNotificationConfigurationPrivate.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "TDCChannelPropertiesSheetPrivate.h"
#import "TLONotificationController.h"
#import "TLONotificationConfigurationPrivate.h"
NS_ASSUME_NONNULL_BEGIN
@interface TDCChannelPropertiesNotificationConfiguration : TLONotificationConfiguration
- (instancetype)initWithEventType:(TXNotificationType)aEventType inSheet:(TDCChannelPropertiesSheet *)sheet;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Private/TDCChannelPropertiesSheetPrivate.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2008 - 2010 Satoshi Nakagawa
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "TDCSharedProtocolDefinitionsPrivate.h"
#import "TDCSheetBase.h"
NS_ASSUME_NONNULL_BEGIN
@class IRCClient, IRCChannel, IRCChannelConfig;
@protocol TDCChannelPropertiesSheetDelegate;
@interface TDCChannelPropertiesSheet : TDCSheetBase
- (instancetype)initWithChannel:(IRCChannel *)channel NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithClient:(IRCClient *)client;
- (instancetype)initWithClientId:(NSString *)clientId;
- (instancetype)initWithConfig:(nullable IRCChannelConfig *)config;
- (instancetype)initWithConfig:(nullable IRCChannelConfig *)config onClientWithId:(nullable NSString *)clientId;
- (instancetype)initWithConfig:(nullable IRCChannelConfig *)config onClient:(nullable IRCClient *)client NS_DESIGNATED_INITIALIZER;
- (void)start;
@end
@protocol TDCChannelPropertiesSheetDelegate
@required
- (void)channelPropertiesSheet:(TDCChannelPropertiesSheet *)sender onOk:(IRCChannelConfig *)config;
- (void)channelPropertiesSheetWillClose:(TDCChannelPropertiesSheet *)sender;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Private/TDCChannelSpotlightAppearancePrivate.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2018 - 2020 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "TVCAppearance.h"
NS_ASSUME_NONNULL_BEGIN
@interface TDCChannelSpotlightAppearance : TVCApplicationAppearance
#pragma mark -
#pragma mark Search Field
@property (readonly, copy, nullable) NSColor *searchFieldTextColor;
@property (readonly, copy, nullable) NSColor *searchFieldCompletionTextColor;
@property (readonly, copy, nullable) NSColor *searchFieldNoResultsTextColor;
#pragma mark -
#pragma mark Search Result
@property (readonly, copy, nullable) NSColor *searchResultRowSelectionColorActiveWindow;
@property (readonly, copy, nullable) NSColor *searchResultRowSelectionColorInactiveWindow;
@property (readonly) BOOL searchResultRowEmphasized;
@property (readonly, copy, nullable) NSColor *searchResultChannelNameTextColor;
@property (readonly, copy, nullable) NSColor *searchResultChannelDescriptionTextColor;
@property (readonly, copy, nullable) NSColor *searchResultKeyboardShortcutTextColor;
@property (readonly) CGFloat searchResultKeyboardShortcutDeselectedOffset;
@property (readonly) CGFloat searchResultKeyboardShortcutSelectedOffset;
@property (readonly, copy, nullable) NSColor *searchResultSelectedTextColor;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Private/TDCChannelSpotlightControllerPrivate.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "TDCWindowBase.h"
NS_ASSUME_NONNULL_BEGIN
@class IRCChannel;
@protocol TDCChannelSpotlightControllerDelegate;
@interface TDCChannelSpotlightController : TDCWindowBase
@end
@protocol TDCChannelSpotlightControllerDelegate
@required
- (void)channelSpotlightController:(TDCChannelSpotlightController *)sender selectChannel:(IRCChannel *)channel;
- (void)channelSpotlightControllerWillClose:(TDCChannelSpotlightController *)sender;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Private/TDCChannelSpotlightControlsPrivate.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
NS_ASSUME_NONNULL_BEGIN
@interface TDCChannelSpotlightPanel : NSPanel
@end
@interface TDCChannelSpotlightTextField : NSTextField
@end
@interface TDCChannelSpotlightImageView : NSImageView
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Private/TDCChannelSpotlightSearchResultPrivate.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
NS_ASSUME_NONNULL_BEGIN
@class IRCChannel, TDCChannelSpotlightController;
@interface TDCChannelSpotlightSearchResult : NSObject
@property (readonly, weak) IRCChannel *channel;
@property (readonly, copy) NSString *clientId;
@property (readonly, copy) NSNumber *distance;
- (instancetype)init NS_UNAVAILABLE;
- (instancetype)initWithChannel:(IRCChannel *)channel NS_DESIGNATED_INITIALIZER;
- (void)recalculateDistanceWith:(NSString *)searchString;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Private/TDCChannelSpotlightSearchResultsTablePrivate.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
NS_ASSUME_NONNULL_BEGIN
@class TDCChannelSpotlightController;
@interface TDCChannelSpotlightSearchResultRowView : NSTableRowView
- (instancetype)initWithController:(TDCChannelSpotlightController *)controller;
@end
@interface TDCChannelSpotlightSearchResultCellView : NSTableCellView
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Private/TDCFileTransferDialogPrivate.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2008 - 2010 Satoshi Nakagawa
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "TDCWindowBase.h"
NS_ASSUME_NONNULL_BEGIN
@class IRCClient, TDCFileTransferDialogTransferController, TVCBasicTableView;
typedef NS_ENUM(NSUInteger, TDCFileTransferDialogTransferStatus) {
TDCFileTransferDialogTransferStatusComplete,
TDCFileTransferDialogTransferStatusConnecting,
TDCFileTransferDialogTransferStatusFatalError,
TDCFileTransferDialogTransferStatusInitializing,
TDCFileTransferDialogTransferStatusIsListeningAsReceiver,
TDCFileTransferDialogTransferStatusIsListeningAsSender,
TDCFileTransferDialogTransferStatusMappingListeningPort,
TDCFileTransferDialogTransferStatusReceiving,
TDCFileTransferDialogTransferStatusRecoverableError,
TDCFileTransferDialogTransferStatusSending,
TDCFileTransferDialogTransferStatusStopped,
TDCFileTransferDialogTransferStatusWaitingForLocalIPAddress,
TDCFileTransferDialogTransferStatusWaitingForReceiverToAccept,
TDCFileTransferDialogTransferStatusWaitingForResumeAccept
};
typedef NS_ENUM(NSUInteger, TDCFileTransferDialogSelection) {
TDCFileTransferDialogSelectionAll = 0,
TDCFileTransferDialogSelectionSending = 1,
TDCFileTransferDialogSelectionReceiving = 2
};
@class TDCFileTransferDialogTransferController;
@interface TDCFileTransferDialog : TDCWindowBase
@property (readonly, weak) TVCBasicTableView *fileTransferTable;
@property (readonly, copy, nullable) NSString *IPAddress;
- (void)show:(BOOL)makeKeyWindow;
- (void)show:(BOOL)makeKeyWindow restorePosition:(BOOL)restorePosition;
- (void)requestIPAddress; // from external source
- (void)clearIPAddress;
/* The next two method return a unique identifier specific to each
added request. This identifier is different from a request token
as it is available always and never is seen by the other user.
It is used internally for finding specific requests. */
/* Returning nil means that something failed and the transfer was
never added to list of transfers. */
- (nullable NSString *)addReceiverForClient:(IRCClient *)client
nickname:(NSString *)nickname
address:(NSString *)hostAddress
port:(uint16_t)hostPort
filename:(NSString *)filename
filesize:(uint64_t)totalFilesize
token:(nullable NSString *)transferToken;
- (nullable NSString *)addSenderForClient:(IRCClient *)client
nickname:(NSString *)nickname
path:(NSString *)path
autoOpen:(BOOL)autoOpen;
- (BOOL)fileTransferExistsWithToken:(NSString *)transferToken;
- (nullable TDCFileTransferDialogTransferController *)fileTransferMatchingPort:(uint16_t)port;
- (nullable TDCFileTransferDialogTransferController *)fileTransferSenderMatchingToken:(NSString *)transferToken;
- (nullable TDCFileTransferDialogTransferController *)fileTransferReceiverMatchingToken:(NSString *)transferToken;
- (nullable TDCFileTransferDialogTransferController *)fileTransferWithUniqueIdentifier:(NSString *)identifier;
@end
#pragma mark -
@interface TDCFileTransferDialog (TDCFileTransferDialogDownloadDestinationExtension)
- (nullable NSURL *)downloadDestinationURL;
- (void)setDownloadDestinationURL:(nullable NSData *)downloadDestinationURL;
- (void)startUsingDownloadDestinationURL;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Private/TDCFileTransferDialogTableCellPrivate.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2008 - 2010 Satoshi Nakagawa
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
NS_ASSUME_NONNULL_BEGIN
@interface TDCFileTransferDialogTableCell : NSTableCellView
- (void)onMaintenanceTimer;
- (void)reloadStatusInformation;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Private/TDCFileTransferDialogTransferControllerPrivate.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2008 - 2010 Satoshi Nakagawa
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "TDCSharedProtocolDefinitionsPrivate.h"
#import "TDCFileTransferDialogPrivate.h"
NS_ASSUME_NONNULL_BEGIN
@class IRCClient, TDCFileTransferDialogTableCell;
@interface TDCFileTransferDialogTransferController : NSObject
@property (nonatomic, weak) TDCFileTransferDialogTableCell *transferTableCell;
@property (readonly) BOOL isResume;
@property (readonly) BOOL isReversed;
@property (readonly) BOOL isSender;
@property (readonly) TDCFileTransferDialogTransferStatus transferStatus;
@property (readonly) uint64_t totalFilesize;
@property (readonly) uint64_t processedFilesize;
@property (readonly) uint64_t currentRecord;
@property (readonly, copy) NSArray *speedRecords;
@property (readonly, copy, nullable) NSString *errorMessageDescription;
@property (readonly, copy, nullable) NSString *path;
@property (readonly, copy) NSString *filename;
@property (readonly, copy, nullable) NSString *filePath;
@property (readonly, copy, nullable) NSURL *fileURL;
@property (readonly, copy) NSString *hostAddress;
@property (readonly, copy) NSString *peerNickname;
@property (readonly, copy, nullable) NSString *transferToken;
@property (readonly, copy) NSString *uniqueIdentifier;
@property (readonly) uint16_t hostPort;
@property (getter=isActingAsClient, readonly) BOOL actingAsClient;
@property (getter=isActingAsServer, readonly) BOOL actingAsServer;
+ (nullable instancetype)receiverForClient:(IRCClient *)client
nickname:(NSString *)nickname
address:(NSString *)hostAddress
port:(uint16_t)hostPort
filename:(NSString *)filename
filesize:(uint64_t)totalFilesize
token:(nullable NSString *)transferToken;
+ (nullable instancetype)senderForClient:(IRCClient *)client
nickname:(NSString *)nickname
path:(NSString *)path;
- (instancetype)init NS_UNAVAILABLE;
- (void)open;
- (void)openWithPathOrUserDownloads;
- (void)openWithPath:(nullable NSString *)path; // Only changes path if self.path == nil
- (void)close;
- (void)closeAndPostNotification:(BOOL)postNotification;
- (void)sendTransferRequestToClient;
- (void)noteIPAddressLookupFailed;
- (void)noteIPAddressLookupSucceeded;
- (void)didReceiveSendRequest:(NSString *)hostAddress hostPort:(uint16_t)hostPort;
- (void)didReceiveResumeAccept:(uint64_t)proposedPosition;
- (void)didReceiveResumeRequest:(uint64_t)proposedPosition;
- (void)onMaintenanceTimer;
- (void)updateClearButton;
- (void)reloadStatusInformation;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Private/TDCHighlightEntrySheetPrivate.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "TDCSheetBase.h"
NS_ASSUME_NONNULL_BEGIN
@class IRCChannelConfig, IRCHighlightMatchCondition;
@interface TDCHighlightEntrySheet : TDCSheetBase
- (instancetype)initWithConfig:(nullable IRCHighlightMatchCondition *)config NS_DESIGNATED_INITIALIZER;
- (void)startWithChannels:(NSArray *)channels;
@end
@protocol TDCHighlightEntrySheetDelegate
@required
- (void)highlightEntrySheet:(TDCHighlightEntrySheet *)sender onOk:(IRCHighlightMatchCondition *)config;
- (void)highlightEntrySheetWillClose:(TDCHighlightEntrySheet *)sender;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Private/TDCLicenseManagerDialogPrivate.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "TDCWindowBase.h"
NS_ASSUME_NONNULL_BEGIN
#if TEXTUAL_BUILT_WITH_LICENSE_MANAGER == 1
TEXTUAL_EXTERN NSNotificationName const TDCLicenseManagerActivatedLicenseNotification;
TEXTUAL_EXTERN NSNotificationName const TDCLicenseManagerDeactivatedLicenseNotification;
TEXTUAL_EXTERN NSNotificationName const TDCLicenseManagerTrialExpiredNotification;
@interface TDCLicenseManagerDialog : TDCWindowBase
- (void)activateLicenseKey:(NSString *)licenseKey;
- (void)activateLicenseKey:(NSString *)licenseKey silently:(BOOL)silently;
- (NSString *)timeRemainingInTrialFormattedMessage;
@end
#endif
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Private/TDCLicenseManagerMigrateAppStoreSheetPrivate.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "TDCSheetBase.h"
NS_ASSUME_NONNULL_BEGIN
#if TEXTUAL_BUILT_WITH_LICENSE_MANAGER == 1
@interface TDCLicenseManagerMigrateAppStoreSheet : TDCSheetBase
- (void)start;
@end
@protocol TDCLicenseManagerMigrateAppStoreSheetDelegate
@required
- (void)licenseManagerMigrateAppStoreSheet:(TDCLicenseManagerMigrateAppStoreSheet *)sender
convertReceipt:(NSString *)receiptData
licenseOwnerName:(NSString *)licenseOwnerName
licenseOwnerContactAddress:(NSString *)licenseOwnerContactAddress;
- (void)licenseManagerMigrateAppStoreSheetWillClose:(TDCLicenseManagerMigrateAppStoreSheet *)sender;
@end
#endif
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Private/TDCLicenseManagerRecoverLostLicenseSheetPrivate.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "TDCSheetBase.h"
NS_ASSUME_NONNULL_BEGIN
#if TEXTUAL_BUILT_WITH_LICENSE_MANAGER == 1
@interface TDCLicenseManagerRecoverLostLicenseSheet : TDCSheetBase
- (void)start;
@end
@protocol TDCLicenseManagerRecoverLostLicenseSheet
@required
- (void)licenseManagerRecoverLostLicenseSheet:(TDCLicenseManagerRecoverLostLicenseSheet *)sender onOk:(NSString *)contactAddress;
- (void)licenseManagerRecoverLostLicenseSheetWillClose:(TDCLicenseManagerRecoverLostLicenseSheet *)sender;
@end
#endif
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Private/TDCLicenseUpgradeActivateSheetPrivate.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "TDCSheetBase.h"
#import "TDCLicenseUpgradeEligibilitySheetPrivate.h"
NS_ASSUME_NONNULL_BEGIN
#if TEXTUAL_BUILT_WITH_LICENSE_MANAGER == 1
@protocol TDCLicenseUpgradeActivateSheetDelegate;
@interface TDCLicenseUpgradeActivateSheet : TDCSheetBase
@property (readonly, copy) NSString *licenseKey;
@property (readonly) TLOLicenseUpgradeEligibility eligibility;
- (instancetype)initWithLicenseKey:(NSString *)licenseKey
eligibility:(TLOLicenseUpgradeEligibility)eligibility NS_DESIGNATED_INITIALIZER;
- (void)start;
@end
@protocol TDCLicenseUpgradeActivateSheetDelegate
@required
- (void)upgradeActivateSheetActivateLicense:(TDCLicenseUpgradeActivateSheet *)sender;
- (void)upgradeActivateSheetPurchaseUpgrade:(TDCLicenseUpgradeActivateSheet *)sender;
- (void)upgradeActivateSheetSuppressed:(TDCLicenseUpgradeActivateSheet *)sender;
- (void)upgradeActivateSheetWillClose:(TDCLicenseUpgradeActivateSheet *)sender;
@end
#endif
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Private/TDCLicenseUpgradeCommonActionsPrivate.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
NS_ASSUME_NONNULL_BEGIN
#if TEXTUAL_BUILT_WITH_LICENSE_MANAGER == 1
@interface TDCLicenseUpgradeCommonActions : NSObject
+ (void)contactSupport;
+ (void)activateLicense:(NSString *)licenseKey;
+ (void)purchaseUpgradeForLicense:(NSString *)licenseKey;
+ (void)learnMore;
+ (void)openStandaloneStore;
@end
#endif
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Private/TDCLicenseUpgradeDialogPrivate.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "TDCWindowBase.h"
#import "TLOLicenseManagerLastGenPrivate.h"
#import "TDCLicenseUpgradeEligibilitySheetPrivate.h"
NS_ASSUME_NONNULL_BEGIN
#if TEXTUAL_BUILT_WITH_LICENSE_MANAGER == 1
@protocol TDCLicenseUpgradeDialogDelegate;
@interface TDCLicenseUpgradeDialog : TDCWindowBase
@property (readonly, copy) NSString *licenseKey;
@property (readonly) TLOLicenseUpgradeEligibility eligibility;
- (instancetype)init NS_UNAVAILABLE;
- (instancetype)initWithLicenseKey:(NSString *)licenseKey NS_DESIGNATED_INITIALIZER;
@end
@protocol TDCLicenseUpgradeDialogDelegate
@required
- (void)licenseUpgradeDialogEligibilityChanged:(TDCLicenseUpgradeDialog *)sender;
- (void)licenseUpgradeDialogWRemindMeLater:(TDCLicenseUpgradeDialog *)sender;
- (void)licenseUpgradeDialogWillClose:(TDCLicenseUpgradeDialog *)sender;
@end
#endif
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Private/TDCLicenseUpgradeEligibilitySheetPrivate.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "TDCSheetBase.h"
NS_ASSUME_NONNULL_BEGIN
#if TEXTUAL_BUILT_WITH_LICENSE_MANAGER == 1
typedef NS_ENUM(NSUInteger, TLOLicenseUpgradeEligibility) {
TLOLicenseUpgradeEligibilityUnknown = LONG_MAX,
TLOLicenseUpgradeEligibilityNot = 0,
TLOLicenseUpgradeEligibilityDiscount = 1,
TLOLicenseUpgradeEligibilityFree = 3,
TLOLicenseUpgradeEligibilityAlreadyUpgraded = 2,
};
@protocol TDCLicenseUpgradeEligibilitySheetDelegate;
@interface TDCLicenseUpgradeEligibilitySheet : TDCSheetBase
@property (readonly, copy) NSString *licenseKey;
@property (readonly) TLOLicenseUpgradeEligibility eligibility;
- (instancetype)initWithLicenseKey:(NSString *)licenseKey NS_DESIGNATED_INITIALIZER;
- (void)checkEligibility;
@end
@protocol TDCLicenseUpgradeEligibilitySheetDelegate
@required
- (void)upgradeEligibilitySheetContactSupport:(TDCLicenseUpgradeEligibilitySheet *)sender;
- (void)upgradeEligibilitySheetActivateLicense:(TDCLicenseUpgradeEligibilitySheet *)sender;
- (void)upgradeEligibilitySheetPurchaseUpgrade:(TDCLicenseUpgradeEligibilitySheet *)sender;
- (void)upgradeEligibilitySheetPurchaseStandalone:(TDCLicenseUpgradeEligibilitySheet *)sender;
- (void)upgradeEligibilitySheetChanged:(TDCLicenseUpgradeEligibilitySheet *)sender;
- (void)upgradeEligibilitySheetWillClose:(TDCLicenseUpgradeEligibilitySheet *)sender;
@end
#endif
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Private/TDCNicknameColorSheetPrivate.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "TDCSheetBase.h"
NS_ASSUME_NONNULL_BEGIN
@interface TDCNicknameColorSheet : TDCSheetBase
- (instancetype)initWithNickname:(NSString *)nickname NS_DESIGNATED_INITIALIZER;
- (void)start;
@end
@protocol TDCNicknameColorSheetDelegate
@required
- (void)nicknameColorSheetOnOk:(TDCNicknameColorSheet *)sender;
- (void)nicknameColorSheetWillClose:(TDCNicknameColorSheet *)sender;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Private/TDCPreferencesControllerPrivate.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2008 - 2010 Satoshi Nakagawa
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "TDCWindowBase.h"
NS_ASSUME_NONNULL_BEGIN
typedef NS_ENUM(NSUInteger, TDCPreferencesControllerSelection) {
TDCPreferencesControllerSelectionDefault = 0,
TDCPreferencesControllerSelectionNotifications,
TDCPreferencesControllerSelectionStyle,
TDCPreferencesControllerSelectionHiddenPreferences
};
@protocol TDCPreferencesControllerDelegate;
@interface TDCPreferencesController : TDCWindowBase
+ (void)openProxySettingsInSystemPreferences;
- (void)show:(TDCPreferencesControllerSelection)selection;
@end
@protocol TDCPreferencesControllerDelegate
@required
- (void)preferencesDialogWillClose:(TDCPreferencesController *)sender;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Private/TDCPreferencesNotificationConfigurationPrivate.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2008 - 2010 Satoshi Nakagawa
* Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "TLONotificationController.h"
#import "TLONotificationConfigurationPrivate.h"
NS_ASSUME_NONNULL_BEGIN
@interface TDCPreferencesNotificationConfiguration : TLONotificationConfiguration
+ (TDCPreferencesNotificationConfiguration *)objectWithEventType:(TXNotificationType)eventType;
@end
NS_ASSUME_NONNULL_END
================================================
FILE: Sources/App/Classes/Headers/Private/TDCPreferencesUserStyleSheetPrivate.h
================================================
/* *********************************************************************
* _____ _ _
* |_ _|____ _| |_ _ _ __ _| |
* | |/ _ \ \/ / __| | | |/ _` | |
* | | __/> <| |_| |_| | (_| | |
* |_|\___/_/\_\\__|\__,_|\__,_|_|
*
* Copyright (c) 2019 Codeux Software, LLC & respective contributors.
* Please see Acknowledgements.pdf for additional information.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Textual, "Codeux Software, LLC", nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*********************************************************************** */
#import "TDCSheetBase.h"
NS_ASSUME_NONNULL_BEGIN
@interface TDCPreferencesUserStyleSheet : TDCSheetBase
- (void)start;
@end
@protocol TDCPreferencesUserStyleSheetDelegate