├── icon.png ├── Default.png ├── Tests ├── en.lproj │ └── InfoPlist.strings ├── MumbleTests.pch ├── MUTextMessageProcessorTest.h ├── MumbleTests-Info.plist └── MUTextMessageProcessorTest.m ├── icon7@2x.png ├── icon7@3x.png ├── icon@2x.png ├── iconpad.png ├── Default@2x.png ├── iconpad@2x.png ├── Resources ├── up.png ├── down.png ├── up@2x.png ├── channel.png ├── down@2x.png ├── usermsg.png ├── channel@2x.png ├── channelmsg.png ├── muted_local.png ├── muted_self.png ├── talking_alt.png ├── talking_off.png ├── talking_on.png ├── usermsg@2x.png ├── LogoBigShadow.png ├── authenticated.png ├── certificate16.png ├── certificate32.png ├── certificate64.png ├── channelmsg@2x.png ├── deafened_self.png ├── muted_self@2x.png ├── muted_server.png ├── talkbutton_on.png ├── talking_on@2x.png ├── Apple │ ├── Balloon_2.png │ ├── Balloon_2@2x.png │ ├── Balloon_Blue.png │ ├── Balloon_2_Right.png │ ├── Balloon_Blue@2x.png │ ├── GrayCheckmark.png │ ├── GrayCheckmark@2x.png │ ├── Balloon_2_Right@2x.png │ ├── LeftBalloonSelected.png │ ├── RightBalloonSelected.png │ ├── LeftBalloonSelected@2x.png │ ├── LeftBalloonSelectedMono.png │ ├── RightBalloonSelected@2x.png │ ├── RightBalloonSelectedMono.png │ ├── LeftBalloonSelectedMono@2x.png │ ├── RightBalloonSelectedMono@2x.png │ ├── _UIPopoverViewBlackBackgroundArrowUp.png │ ├── _UIPopoverViewBlackBackgroundArrowUp@2x.png │ └── README ├── LogoBigShadow@2x.png ├── MumbleMenuButton.png ├── SmallMumbleIcon.png ├── authenticated@2x.png ├── certificate128.png ├── certificate256.png ├── certificate512.png ├── certificatecell.png ├── deafened_self@2x.png ├── deafened_server.png ├── muted_local@2x.png ├── muted_server@2x.png ├── muted_suppressed.png ├── priorityspeaker.png ├── talkbutton_off.png ├── talkbutton_on@2x.png ├── talking_alt@2x.png ├── talking_off@2x.png ├── talking_whisper.png ├── SmallMumbleIcon@2x.png ├── WelcomeScreenIcon.png ├── certificatecell@2x.png ├── deafened_server@2x.png ├── priorityspeaker@2x.png ├── talkbutton_off@2x.png ├── talking_whisper@2x.png ├── BlackToolbarPattern.png ├── MumbleMenuButton@2x.png ├── WelcomeScreenIcon@2x.png ├── certificatecreation.png ├── muted_suppressed@2x.png ├── BlackToolbarPattern@2x.png ├── BlackToolbarPatterniOS7.png ├── certificatecreation@2x.png ├── BlackToolbarPatterniOS7@2x.png ├── WelcomeScreenIcon-568h@2x.png ├── certificatecell-selected.png ├── da.lproj │ └── Localizable.strings ├── en.lproj │ └── Localizable.strings ├── certificatecell-intermediate.png ├── certificatecell-selected@2x.png ├── BackgroundTextureBlackGradient.png ├── certificatecell-intermediate@2x.png ├── BackgroundTextureBlackGradient@2x.png ├── BackgroundTextureBlackGradientPad.png ├── BackgroundTextureBlackGradientPad@2x.png ├── BackgroundTextureBlackGradient-568h@2x.png ├── UIElements │ ├── MUServerButton │ │ └── MUServerButton.pcvd │ └── MUActionSheet │ │ ├── MUActionSheetButtonCancel.pcvd │ │ ├── MUActionSheetButtonNormal.pcvd │ │ ├── MUActionSheetBackgroundView.pcvd │ │ ├── MUActionSheetButtonDestructive.pcvd │ │ ├── MUActionSheetButtonBlueHighlight.pcvd │ │ ├── MUActionSheetButtonConstructive.pcvd │ │ └── MUActionSheetButtonGrayHighlight.pcvd ├── README └── Continents.plist ├── iTunesArtwork.png ├── Default-568h@2x.png ├── Default-iOS7@2x.png ├── Scripts ├── fetch-publist ├── update-localization └── gen-country-plist.py ├── Default-iOS7-568h@2x.png ├── .gitignore ├── .gitmodules ├── Mumble.xcodeproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── xcshareddata │ └── xcschemes │ └── Mumble.xcscheme ├── .tx └── config ├── Source ├── Mumble.pch ├── Classes │ ├── MUWelcomeScreenPad.h │ ├── MULegalViewController.h │ ├── MUPopoverBackgroundView.h │ ├── MUAudioMixerDebugViewController.h │ ├── MUWelcomeScreenPhone.h │ ├── MUVoiceActivitySetupViewController.h │ ├── MUCertificatePreferencesViewController.h │ ├── MUPreferencesViewController.h │ ├── MUAudioQualityPreferencesViewController.h │ ├── MUBackgroundView.h │ ├── MURemoteControlPreferencesViewController.h │ ├── MUAdvancedAudioPreferencesViewController.h │ ├── MUAudioSidetonePreferencesViewController.h │ ├── MUImageViewController.h │ ├── MUApplicationDelegate.h │ ├── MUAudioBarView.h │ ├── MUAudioTransmissionPreferencesViewController.h │ ├── MUHorizontalFlipTransitionDelegate.h │ ├── MUServerTableViewCell.h │ ├── MUTextMessageProcessor.h │ ├── MUCertificateChainBuilder.h │ ├── MULanServerListController.h │ ├── MUUserStateAcessoryView.h │ ├── MUDataURL.h │ ├── MUCertificateCreationView.h │ ├── MUPublicServerListController.h │ ├── MUAudioBarViewCell.h │ ├── MUCertificateCreationProgressView.h │ ├── MUMessagesViewController.h │ ├── MUCertificateDiskImportViewController.h │ ├── MURemoteControlServer.h │ ├── MUAccessTokenViewController.h │ ├── MUImage.h │ ├── MUTableViewHeaderLabel.h │ ├── MUMessageAttachmentViewController.h │ ├── MUNotificationController.h │ ├── MUCountryServerListController.h │ ├── MUServerButton.h │ ├── MUFavouriteServerListController.h │ ├── MUColor.h │ ├── MUServerRootViewController.h │ ├── MUMessagesDatabase.h │ ├── MUServerViewController.h │ ├── MUServerCell.h │ ├── MUCertificateViewController.h │ ├── MUPublicServerList.h │ ├── MUConnectionController.h │ ├── MUBackgroundView.m │ ├── MUCertificateController.h │ ├── MUFavouriteServerEditViewController.h │ ├── MUCertificateCell.h │ ├── MUServerCertificateTrustViewController.h │ ├── MUFavouriteServer.h │ ├── MainWindow~iPad.xib │ ├── MUMessageRecipientViewController.h │ ├── MUTextMessage.h │ ├── MUTableViewHeaderLabel.m │ ├── MUServerTableViewCell.m │ ├── MUColor.m │ ├── MUAudioBarViewCell.m │ ├── MUDatabase.h │ ├── MUMessageBubbleTableViewCell.h │ ├── MULegalViewController.m │ ├── MUDataURL.m │ ├── MUPopoverBackgroundView.m │ ├── MUServerCertificateTrustViewController.m │ ├── MUUserStateAcessoryView.m │ ├── MUFavouriteServer.m │ ├── MUTextMessage.m │ ├── MUHorizontalFlipTransitionDelegate.m │ ├── MULegalViewController.xib │ ├── MUCertificateCell.m │ ├── MUCertificateCreationProgressView.m │ ├── MUTextMessageProcessor.m │ ├── MUImage.m │ ├── MURemoteControlPreferencesViewController.m │ ├── MUAudioMixerDebugViewController.m │ ├── MUNotificationController.m │ ├── MUAudioBarView.m │ ├── MUPublicServerListController.m │ ├── MUAudioSidetonePreferencesViewController.m │ ├── MUMessageAttachmentViewController.m │ ├── MURemoteControlServer.m │ ├── MUMessagesDatabase.m │ ├── MUCertificateController.m │ ├── LaunchScreen.storyboard │ ├── MUImageViewController.m │ ├── MUServerCell.m │ ├── MUAudioQualityPreferencesViewController.m │ ├── MUCertificateCreationProgressView.xib │ └── MUPublicServerList.m ├── main.m ├── MainWindow.xib └── Info.plist ├── BuildConfig ├── BetaDist.xcconfig ├── AppStore.xcconfig ├── Debug.xcconfig ├── Release.xcconfig └── Base.xcconfig ├── AUTHORS ├── CONTRIBUTORS ├── .github └── workflows │ └── build.yml ├── LICENSE ├── README.markdown └── Dependencies └── MKNumberBadgeView └── MKNumberBadgeView.h /icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/icon.png -------------------------------------------------------------------------------- /Default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Default.png -------------------------------------------------------------------------------- /Tests/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /icon7@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/icon7@2x.png -------------------------------------------------------------------------------- /icon7@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/icon7@3x.png -------------------------------------------------------------------------------- /icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/icon@2x.png -------------------------------------------------------------------------------- /iconpad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/iconpad.png -------------------------------------------------------------------------------- /Default@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Default@2x.png -------------------------------------------------------------------------------- /iconpad@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/iconpad@2x.png -------------------------------------------------------------------------------- /Resources/up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/up.png -------------------------------------------------------------------------------- /iTunesArtwork.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/iTunesArtwork.png -------------------------------------------------------------------------------- /Default-568h@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Default-568h@2x.png -------------------------------------------------------------------------------- /Default-iOS7@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Default-iOS7@2x.png -------------------------------------------------------------------------------- /Resources/down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/down.png -------------------------------------------------------------------------------- /Resources/up@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/up@2x.png -------------------------------------------------------------------------------- /Scripts/fetch-publist: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | curl http://dk.mumble.info/list2.cgi > Resources/publist.xml 3 | -------------------------------------------------------------------------------- /Scripts/update-localization: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | genstrings -o Resources/en.lproj Source/Classes/*.m 3 | -------------------------------------------------------------------------------- /Resources/channel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/channel.png -------------------------------------------------------------------------------- /Resources/down@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/down@2x.png -------------------------------------------------------------------------------- /Resources/usermsg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/usermsg.png -------------------------------------------------------------------------------- /Default-iOS7-568h@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Default-iOS7-568h@2x.png -------------------------------------------------------------------------------- /Resources/channel@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/channel@2x.png -------------------------------------------------------------------------------- /Resources/channelmsg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/channelmsg.png -------------------------------------------------------------------------------- /Resources/muted_local.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/muted_local.png -------------------------------------------------------------------------------- /Resources/muted_self.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/muted_self.png -------------------------------------------------------------------------------- /Resources/talking_alt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/talking_alt.png -------------------------------------------------------------------------------- /Resources/talking_off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/talking_off.png -------------------------------------------------------------------------------- /Resources/talking_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/talking_on.png -------------------------------------------------------------------------------- /Resources/usermsg@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/usermsg@2x.png -------------------------------------------------------------------------------- /Resources/LogoBigShadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/LogoBigShadow.png -------------------------------------------------------------------------------- /Resources/authenticated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/authenticated.png -------------------------------------------------------------------------------- /Resources/certificate16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/certificate16.png -------------------------------------------------------------------------------- /Resources/certificate32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/certificate32.png -------------------------------------------------------------------------------- /Resources/certificate64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/certificate64.png -------------------------------------------------------------------------------- /Resources/channelmsg@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/channelmsg@2x.png -------------------------------------------------------------------------------- /Resources/deafened_self.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/deafened_self.png -------------------------------------------------------------------------------- /Resources/muted_self@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/muted_self@2x.png -------------------------------------------------------------------------------- /Resources/muted_server.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/muted_server.png -------------------------------------------------------------------------------- /Resources/talkbutton_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/talkbutton_on.png -------------------------------------------------------------------------------- /Resources/talking_on@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/talking_on@2x.png -------------------------------------------------------------------------------- /Resources/Apple/Balloon_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/Apple/Balloon_2.png -------------------------------------------------------------------------------- /Resources/LogoBigShadow@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/LogoBigShadow@2x.png -------------------------------------------------------------------------------- /Resources/MumbleMenuButton.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/MumbleMenuButton.png -------------------------------------------------------------------------------- /Resources/SmallMumbleIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/SmallMumbleIcon.png -------------------------------------------------------------------------------- /Resources/authenticated@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/authenticated@2x.png -------------------------------------------------------------------------------- /Resources/certificate128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/certificate128.png -------------------------------------------------------------------------------- /Resources/certificate256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/certificate256.png -------------------------------------------------------------------------------- /Resources/certificate512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/certificate512.png -------------------------------------------------------------------------------- /Resources/certificatecell.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/certificatecell.png -------------------------------------------------------------------------------- /Resources/deafened_self@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/deafened_self@2x.png -------------------------------------------------------------------------------- /Resources/deafened_server.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/deafened_server.png -------------------------------------------------------------------------------- /Resources/muted_local@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/muted_local@2x.png -------------------------------------------------------------------------------- /Resources/muted_server@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/muted_server@2x.png -------------------------------------------------------------------------------- /Resources/muted_suppressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/muted_suppressed.png -------------------------------------------------------------------------------- /Resources/priorityspeaker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/priorityspeaker.png -------------------------------------------------------------------------------- /Resources/talkbutton_off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/talkbutton_off.png -------------------------------------------------------------------------------- /Resources/talkbutton_on@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/talkbutton_on@2x.png -------------------------------------------------------------------------------- /Resources/talking_alt@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/talking_alt@2x.png -------------------------------------------------------------------------------- /Resources/talking_off@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/talking_off@2x.png -------------------------------------------------------------------------------- /Resources/talking_whisper.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/talking_whisper.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/* 2 | MumbleKit/build/* 3 | .DS_Store 4 | *.pbxuser 5 | *.mode1v3 6 | project.xcworkspace 7 | xcuserdata 8 | -------------------------------------------------------------------------------- /Resources/Apple/Balloon_2@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/Apple/Balloon_2@2x.png -------------------------------------------------------------------------------- /Resources/Apple/Balloon_Blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/Apple/Balloon_Blue.png -------------------------------------------------------------------------------- /Resources/SmallMumbleIcon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/SmallMumbleIcon@2x.png -------------------------------------------------------------------------------- /Resources/WelcomeScreenIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/WelcomeScreenIcon.png -------------------------------------------------------------------------------- /Resources/certificatecell@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/certificatecell@2x.png -------------------------------------------------------------------------------- /Resources/deafened_server@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/deafened_server@2x.png -------------------------------------------------------------------------------- /Resources/priorityspeaker@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/priorityspeaker@2x.png -------------------------------------------------------------------------------- /Resources/talkbutton_off@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/talkbutton_off@2x.png -------------------------------------------------------------------------------- /Resources/talking_whisper@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/talking_whisper@2x.png -------------------------------------------------------------------------------- /Resources/Apple/Balloon_2_Right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/Apple/Balloon_2_Right.png -------------------------------------------------------------------------------- /Resources/Apple/Balloon_Blue@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/Apple/Balloon_Blue@2x.png -------------------------------------------------------------------------------- /Resources/Apple/GrayCheckmark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/Apple/GrayCheckmark.png -------------------------------------------------------------------------------- /Resources/BlackToolbarPattern.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/BlackToolbarPattern.png -------------------------------------------------------------------------------- /Resources/MumbleMenuButton@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/MumbleMenuButton@2x.png -------------------------------------------------------------------------------- /Resources/WelcomeScreenIcon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/WelcomeScreenIcon@2x.png -------------------------------------------------------------------------------- /Resources/certificatecreation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/certificatecreation.png -------------------------------------------------------------------------------- /Resources/muted_suppressed@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/muted_suppressed@2x.png -------------------------------------------------------------------------------- /Resources/Apple/GrayCheckmark@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/Apple/GrayCheckmark@2x.png -------------------------------------------------------------------------------- /Resources/BlackToolbarPattern@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/BlackToolbarPattern@2x.png -------------------------------------------------------------------------------- /Resources/BlackToolbarPatterniOS7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/BlackToolbarPatterniOS7.png -------------------------------------------------------------------------------- /Resources/certificatecreation@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/certificatecreation@2x.png -------------------------------------------------------------------------------- /Resources/Apple/Balloon_2_Right@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/Apple/Balloon_2_Right@2x.png -------------------------------------------------------------------------------- /Resources/Apple/LeftBalloonSelected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/Apple/LeftBalloonSelected.png -------------------------------------------------------------------------------- /Resources/Apple/RightBalloonSelected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/Apple/RightBalloonSelected.png -------------------------------------------------------------------------------- /Resources/BlackToolbarPatterniOS7@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/BlackToolbarPatterniOS7@2x.png -------------------------------------------------------------------------------- /Resources/WelcomeScreenIcon-568h@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/WelcomeScreenIcon-568h@2x.png -------------------------------------------------------------------------------- /Resources/certificatecell-selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/certificatecell-selected.png -------------------------------------------------------------------------------- /Resources/da.lproj/Localizable.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/da.lproj/Localizable.strings -------------------------------------------------------------------------------- /Resources/en.lproj/Localizable.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/en.lproj/Localizable.strings -------------------------------------------------------------------------------- /Resources/Apple/LeftBalloonSelected@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/Apple/LeftBalloonSelected@2x.png -------------------------------------------------------------------------------- /Resources/certificatecell-intermediate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/certificatecell-intermediate.png -------------------------------------------------------------------------------- /Resources/certificatecell-selected@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/certificatecell-selected@2x.png -------------------------------------------------------------------------------- /Resources/Apple/LeftBalloonSelectedMono.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/Apple/LeftBalloonSelectedMono.png -------------------------------------------------------------------------------- /Resources/Apple/RightBalloonSelected@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/Apple/RightBalloonSelected@2x.png -------------------------------------------------------------------------------- /Resources/Apple/RightBalloonSelectedMono.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/Apple/RightBalloonSelectedMono.png -------------------------------------------------------------------------------- /Resources/BackgroundTextureBlackGradient.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/BackgroundTextureBlackGradient.png -------------------------------------------------------------------------------- /Resources/certificatecell-intermediate@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/certificatecell-intermediate@2x.png -------------------------------------------------------------------------------- /Resources/Apple/LeftBalloonSelectedMono@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/Apple/LeftBalloonSelectedMono@2x.png -------------------------------------------------------------------------------- /Resources/Apple/RightBalloonSelectedMono@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/Apple/RightBalloonSelectedMono@2x.png -------------------------------------------------------------------------------- /Resources/BackgroundTextureBlackGradient@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/BackgroundTextureBlackGradient@2x.png -------------------------------------------------------------------------------- /Resources/BackgroundTextureBlackGradientPad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/BackgroundTextureBlackGradientPad.png -------------------------------------------------------------------------------- /Resources/BackgroundTextureBlackGradientPad@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/BackgroundTextureBlackGradientPad@2x.png -------------------------------------------------------------------------------- /Resources/BackgroundTextureBlackGradient-568h@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/BackgroundTextureBlackGradient-568h@2x.png -------------------------------------------------------------------------------- /Resources/UIElements/MUServerButton/MUServerButton.pcvd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/UIElements/MUServerButton/MUServerButton.pcvd -------------------------------------------------------------------------------- /Resources/Apple/_UIPopoverViewBlackBackgroundArrowUp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/Apple/_UIPopoverViewBlackBackgroundArrowUp.png -------------------------------------------------------------------------------- /Resources/Apple/_UIPopoverViewBlackBackgroundArrowUp@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/Apple/_UIPopoverViewBlackBackgroundArrowUp@2x.png -------------------------------------------------------------------------------- /Resources/UIElements/MUActionSheet/MUActionSheetButtonCancel.pcvd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/UIElements/MUActionSheet/MUActionSheetButtonCancel.pcvd -------------------------------------------------------------------------------- /Resources/UIElements/MUActionSheet/MUActionSheetButtonNormal.pcvd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/UIElements/MUActionSheet/MUActionSheetButtonNormal.pcvd -------------------------------------------------------------------------------- /Resources/UIElements/MUActionSheet/MUActionSheetBackgroundView.pcvd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/UIElements/MUActionSheet/MUActionSheetBackgroundView.pcvd -------------------------------------------------------------------------------- /Resources/UIElements/MUActionSheet/MUActionSheetButtonDestructive.pcvd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/UIElements/MUActionSheet/MUActionSheetButtonDestructive.pcvd -------------------------------------------------------------------------------- /Resources/UIElements/MUActionSheet/MUActionSheetButtonBlueHighlight.pcvd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/UIElements/MUActionSheet/MUActionSheetButtonBlueHighlight.pcvd -------------------------------------------------------------------------------- /Resources/UIElements/MUActionSheet/MUActionSheetButtonConstructive.pcvd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/UIElements/MUActionSheet/MUActionSheetButtonConstructive.pcvd -------------------------------------------------------------------------------- /Resources/UIElements/MUActionSheet/MUActionSheetButtonGrayHighlight.pcvd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mumble-voip/mumble-iphoneos/HEAD/Resources/UIElements/MUActionSheet/MUActionSheetButtonGrayHighlight.pcvd -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "MumbleKit"] 2 | path = MumbleKit 3 | url = https://github.com/mumble-voip/mumblekit.git 4 | [submodule "Dependencies/fmdb"] 5 | path = Dependencies/fmdb 6 | url = https://github.com/ccgus/fmdb.git 7 | -------------------------------------------------------------------------------- /Mumble.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.tx/config: -------------------------------------------------------------------------------- 1 | [main] 2 | host = https://www.transifex.com 3 | 4 | [mumble-iphoneos.app-strings] 5 | file_filter = Resources/.lproj/Localizable.strings 6 | source_file = Resources/en.lproj/Localizable.strings 7 | source_lang = en 8 | type = STRINGS 9 | -------------------------------------------------------------------------------- /Source/Mumble.pch: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2010 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | #ifdef __OBJC__ 6 | @import UIKit; 7 | #endif 8 | -------------------------------------------------------------------------------- /Source/Classes/MUWelcomeScreenPad.h: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | @interface MUWelcomeScreenPad : UIViewController 6 | @end 7 | -------------------------------------------------------------------------------- /Source/Classes/MULegalViewController.h: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2011 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | @interface MULegalViewController : UIViewController 6 | @end 7 | -------------------------------------------------------------------------------- /BuildConfig/BetaDist.xcconfig: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | #include "Release.xcconfig" 6 | 7 | GCC_PREPROCESSOR_DEFINITIONS = MUMBLE_BETA_DIST=1 -------------------------------------------------------------------------------- /BuildConfig/AppStore.xcconfig: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | #include "Release.xcconfig" 6 | 7 | GCC_PREPROCESSOR_DEFINITIONS = MUMBLE_APP_STORE=1 8 | -------------------------------------------------------------------------------- /Source/Classes/MUPopoverBackgroundView.h: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2012 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | @interface MUPopoverBackgroundView : UIPopoverBackgroundView 6 | @end 7 | -------------------------------------------------------------------------------- /Source/Classes/MUAudioMixerDebugViewController.h: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | @interface MUAudioMixerDebugViewController : UITableViewController 6 | @end 7 | -------------------------------------------------------------------------------- /Source/Classes/MUWelcomeScreenPhone.h: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2010 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | @interface MUWelcomeScreenPhone : UITableViewController 6 | - (id) init; 7 | @end 8 | -------------------------------------------------------------------------------- /Tests/MumbleTests.pch: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | #ifdef __OBJC__ 6 | #import 7 | #import 8 | #endif 9 | -------------------------------------------------------------------------------- /Source/Classes/MUVoiceActivitySetupViewController.h: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2011 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | @interface MUVoiceActivitySetupViewController : UITableViewController 6 | @end 7 | -------------------------------------------------------------------------------- /Source/Classes/MUCertificatePreferencesViewController.h: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2010 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | @interface MUCertificatePreferencesViewController : UITableViewController 6 | @end -------------------------------------------------------------------------------- /Source/Classes/MUPreferencesViewController.h: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2010 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | @interface MUPreferencesViewController : UITableViewController 6 | - (id) init; 7 | @end 8 | -------------------------------------------------------------------------------- /Source/Classes/MUAudioQualityPreferencesViewController.h: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2011 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | @interface MUAudioQualityPreferencesViewController : UITableViewController 6 | @end 7 | -------------------------------------------------------------------------------- /Source/Classes/MUBackgroundView.h: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | @import UIKit; 6 | 7 | @interface MUBackgroundView : UIView 8 | + (UIView *) backgroundView; 9 | @end 10 | -------------------------------------------------------------------------------- /Source/Classes/MURemoteControlPreferencesViewController.h: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | @interface MURemoteControlPreferencesViewController : UITableViewController 6 | @end 7 | -------------------------------------------------------------------------------- /Source/Classes/MUAdvancedAudioPreferencesViewController.h: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2011 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | @interface MUAdvancedAudioPreferencesViewController : UITableViewController 6 | @end 7 | -------------------------------------------------------------------------------- /Source/Classes/MUAudioSidetonePreferencesViewController.h: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2011 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | @interface MUAudioSidetonePreferencesViewController : UITableViewController 6 | @end 7 | -------------------------------------------------------------------------------- /Source/Classes/MUImageViewController.h: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2012 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | @interface MUImageViewController : UIViewController 6 | - (id) initWithImages:(NSArray *)images; 7 | @end 8 | -------------------------------------------------------------------------------- /Resources/Apple/README: -------------------------------------------------------------------------------- 1 | This directory contains Apple artwork extracted using UIKit-Artwork-Extractor. 2 | The artwork in here is not free redistributable, and is (C) Apple Inc. 3 | 4 | Modifications: 5 | 6 | GrayCheckmark.png and GrayCheckmark@2x.png are modified versions of Apple's 7 | UIPreferencesBlueCheck.png and UIPreferencesBlueCheck@2x.png. -------------------------------------------------------------------------------- /Source/Classes/MUApplicationDelegate.h: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2010 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | @interface MUApplicationDelegate : NSObject 6 | - (void) reloadPreferences; 7 | @end 8 | -------------------------------------------------------------------------------- /Source/Classes/MUAudioBarView.h: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2011 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | @interface MUAudioBarView : UIView 6 | - (void) setBelow:(CGFloat)below; 7 | - (void) setAbove:(CGFloat)above; 8 | @end 9 | -------------------------------------------------------------------------------- /Source/Classes/MUAudioTransmissionPreferencesViewController.h: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2011 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | @interface MUAudioTransmissionPreferencesViewController : UITableViewController 6 | @end 7 | -------------------------------------------------------------------------------- /Source/Classes/MUHorizontalFlipTransitionDelegate.h: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | @interface MUHorizontalFlipTransitionDelegate : NSObject 6 | @end 7 | -------------------------------------------------------------------------------- /Tests/MUTextMessageProcessorTest.h: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | #import 6 | 7 | @interface MUTextMessageProcessorTest : SenTestCase 8 | 9 | @end 10 | -------------------------------------------------------------------------------- /BuildConfig/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | #include "Base.xcconfig" 6 | 7 | COPY_PHASE_STRIP = NO 8 | 9 | GCC_OPTIMIZATION_LEVEL = 0 10 | 11 | ENABLE_TESTABILITY = YES 12 | -------------------------------------------------------------------------------- /Source/Classes/MUServerTableViewCell.h: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | @interface MUServerTableViewCell : UITableViewCell 6 | - (id) initWithReuseIdentifier:(NSString *)reuseIdentifier; 7 | @end 8 | -------------------------------------------------------------------------------- /Source/Classes/MUTextMessageProcessor.h: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | @interface MUTextMessageProcessor : NSObject 6 | + (NSString *) processedHTMLFromPlainTextMessage:(NSString *)plain; 7 | @end 8 | -------------------------------------------------------------------------------- /Source/Classes/MUCertificateChainBuilder.h: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | @interface MUCertificateChainBuilder : NSObject 6 | + (NSArray *) buildChainFromPersistentRef:(NSData *)persistentRef; 7 | @end 8 | -------------------------------------------------------------------------------- /Source/Classes/MULanServerListController.h: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2010 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | @import UIKit; 6 | 7 | @interface MULanServerListController : UITableViewController 8 | - (id) init; 9 | @end 10 | -------------------------------------------------------------------------------- /Source/Classes/MUUserStateAcessoryView.h: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2011 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | @class MKUser; 6 | 7 | @interface MUUserStateAcessoryView : NSObject 8 | + (UIView *) viewForUser:(MKUser *)user; 9 | @end 10 | -------------------------------------------------------------------------------- /Source/Classes/MUDataURL.h: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2012 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | @interface MUDataURL : NSObject 6 | + (NSData *) dataFromDataURL:(NSString *)dataURL; 7 | + (UIImage *) imageFromDataURL:(NSString *)dataURL; 8 | @end 9 | -------------------------------------------------------------------------------- /Source/Classes/MUCertificateCreationView.h: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2010 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | @import UIKit; 6 | 7 | @interface MUCertificateCreationView : UITableViewController 8 | - (id) init; 9 | - (void) dealloc; 10 | @end 11 | -------------------------------------------------------------------------------- /Source/Classes/MUPublicServerListController.h: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2010 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | #import "MUPublicServerList.h" 6 | 7 | @interface MUPublicServerListController : UITableViewController 8 | - (id) init; 9 | @end 10 | -------------------------------------------------------------------------------- /Source/Classes/MUAudioBarViewCell.h: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2011 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | @interface MUAudioBarViewCell : UITableViewCell 6 | - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier; 7 | @end 8 | -------------------------------------------------------------------------------- /Source/Classes/MUCertificateCreationProgressView.h: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2010 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | @interface MUCertificateCreationProgressView : UIViewController 6 | - (id) initWithName:(NSString *)name email:(NSString *)email; 7 | @end 8 | -------------------------------------------------------------------------------- /Source/Classes/MUMessagesViewController.h: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2011 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | @interface MUMessagesViewController : UIViewController 6 | - (id) initWithServerModel:(MKServerModel *)model; 7 | - (void) clearAllMessages; 8 | @end 9 | -------------------------------------------------------------------------------- /Source/Classes/MUCertificateDiskImportViewController.h: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2010 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | @interface MUCertificateDiskImportViewController : UITableViewController 6 | 7 | - (id) init; 8 | 9 | @end 10 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | // This file lists the 'Mumble for iOS' Developers, the people 2 | // who collectively hold the copyright to 'Mumble for iOS'. 3 | 4 | Benjamin Jemlich 5 | Jimmy Selgen Nielsen 6 | Jeremy Huddleston 7 | Mikkel Krautz 8 | Stefan Hacker 9 | Thorvald Natvig -------------------------------------------------------------------------------- /CONTRIBUTORS: -------------------------------------------------------------------------------- 1 | // This is the official list of people who can contribute 2 | // (and typically have contributed) code to 'Mumble for iOS'. 3 | 4 | Benjamin Jemlich 5 | Jimmy Selgen Nielsen 6 | Jeremy Huddleston 7 | Mikkel Krautz 8 | Stefan Hacker 9 | Thorvald Natvig -------------------------------------------------------------------------------- /Resources/README: -------------------------------------------------------------------------------- 1 | Icons made for Mumble for iOS. 2 | Licensed under the same terms as the program itself. 3 | (Except for the ones listed below) 4 | 5 | Exceptions 6 | ========== 7 | 8 | Glyphish Icons by Jospeh Wain (Creative Commons Attribution 3.0 United States License) 9 | -------------------------------------------------------------------------------------- 10 | connection.png 11 | radar.png 12 | 13 | -------------------------------------------------------------------------------- /Source/Classes/MURemoteControlServer.h: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | @interface MURemoteControlServer : NSObject 6 | + (MURemoteControlServer *) sharedRemoteControlServer; 7 | - (BOOL) isRunning; 8 | - (BOOL) start; 9 | - (BOOL) stop; 10 | @end 11 | -------------------------------------------------------------------------------- /Source/Classes/MUAccessTokenViewController.h: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2011 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | #import 6 | 7 | @interface MUAccessTokenViewController : UITableViewController 8 | - (id) initWithServerModel:(MKServerModel *)model; 9 | @end 10 | -------------------------------------------------------------------------------- /Source/Classes/MUImage.h: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2012 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | @interface MUImage : NSObject 6 | + (UIImage *) tableViewCellImageFromImage:(UIImage *)srcImage; 7 | + (UIImage *) imageNamed:(NSString *)imageName; 8 | + (UIImage *) clearColorImage; 9 | @end 10 | -------------------------------------------------------------------------------- /Source/Classes/MUTableViewHeaderLabel.h: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2011 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | @import UIKit; 6 | 7 | @interface MUTableViewHeaderLabel : UILabel 8 | + (MUTableViewHeaderLabel *) labelWithText:(NSString *)text; 9 | + (CGFloat) defaultHeaderHeight; 10 | @end 11 | -------------------------------------------------------------------------------- /Source/Classes/MUMessageAttachmentViewController.h: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2012 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | @import UIKit; 6 | 7 | @interface MUMessageAttachmentViewController : UITableViewController 8 | - (id) initWithImages:(NSArray *)images andLinks:(NSArray *)links; 9 | @end 10 | -------------------------------------------------------------------------------- /BuildConfig/Release.xcconfig: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | #include "Base.xcconfig" 6 | 7 | COPY_PHASE_STRIP = YES 8 | 9 | CODE_SIGN_IDENTITY = iPhone Distribution: Mikkel Krautz 10 | 11 | GCC_FAST_MATH = YES 12 | GCC_UNROLL_LOOPS = YES 13 | GCC_OPTIMIZATION_LEVEL = 3 -------------------------------------------------------------------------------- /Source/Classes/MUNotificationController.h: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2011 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | @import Foundation; 6 | 7 | @interface MUNotificationController : NSObject 8 | + (MUNotificationController *) sharedController; 9 | - (void) addNotification:(NSString *)text; 10 | @end 11 | -------------------------------------------------------------------------------- /Source/Classes/MUCountryServerListController.h: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2010 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | @interface MUCountryServerListController : UIViewController 6 | - (id) initWithName:(NSString *)country serverList:(NSArray *)servers; 7 | - (void) presentAddAsFavouriteDialogForServer:(NSDictionary *)serverItem; 8 | @end 9 | -------------------------------------------------------------------------------- /Resources/Continents.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | EU 6 | Europe 7 | OC 8 | Oceania 9 | SA 10 | South America 11 | AS 12 | Asia 13 | NA 14 | North America 15 | 16 | 17 | -------------------------------------------------------------------------------- /Source/Classes/MUServerButton.h: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | #import "MUFavouriteServer.h" 6 | 7 | @interface MUServerButton : UIControl 8 | - (void) populateFromDisplayName:(NSString *)displayName hostName:(NSString *)hostName port:(NSString *)port; 9 | - (void) populateFromFavouriteServer:(MUFavouriteServer *)favServ; 10 | @end 11 | -------------------------------------------------------------------------------- /Source/Classes/MUFavouriteServerListController.h: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2010 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | #import "MUFavouriteServer.h" 6 | 7 | @interface MUFavouriteServerListController : UITableViewController 8 | - (id) init; 9 | - (void) presentNewFavouriteDialog; 10 | - (void) presentEditDialogForFavourite:(MUFavouriteServer *)favServ; 11 | @end 12 | -------------------------------------------------------------------------------- /Source/Classes/MUColor.h: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2011 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | @interface MUColor : NSObject 6 | + (UIColor *) selectedTextColor; 7 | + (UIColor *) goodPingColor; 8 | + (UIColor *) mediumPingColor; 9 | + (UIColor *) badPingColor; 10 | + (UIColor *) userCountColor; 11 | + (UIColor *) verifiedCertificateChainColor; 12 | + (UIColor *) backgroundViewiOS7Color; 13 | @end 14 | -------------------------------------------------------------------------------- /Source/Classes/MUServerRootViewController.h: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2011 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | #import 6 | #import 7 | 8 | @interface MUServerRootViewController : UINavigationController 9 | - (id) initWithConnection:(MKConnection *)conn andServerModel:(MKServerModel *)model; 10 | - (void) takeOwnershipOfConnectionDelegate; 11 | @end 12 | -------------------------------------------------------------------------------- /Scripts/gen-country-plist.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env/python2.6 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Generate a country plist from the GeoLite GeoIP CSV file. 5 | # 6 | 7 | import sys 8 | import plistlib 9 | 10 | f = open('GeoIPCountryWhois.csv') 11 | s = f.read() 12 | lines = s.split('\n') 13 | countries = {} 14 | for line in lines: 15 | if not len(line): 16 | break 17 | elem = line.split(',') 18 | code = elem[4].strip('"') 19 | country = elem[5].strip('"') 20 | countries[code] = country 21 | plistlib.writePlist(countries, 'Countries.plist') 22 | -------------------------------------------------------------------------------- /Source/Classes/MUMessagesDatabase.h: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2012 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | @class MKTextMessage; 6 | @class MUTextMessage; 7 | 8 | @interface MUMessagesDatabase : NSObject 9 | - (void) addMessage:(MKTextMessage *)msg withHeading:(NSString *)heading andSentBySelf:(BOOL)selfSent; 10 | - (MUTextMessage *) messageAtIndex:(NSInteger)row; 11 | - (void) clearMessageAtIndex:(NSInteger)row; 12 | - (NSInteger) count; 13 | @end 14 | -------------------------------------------------------------------------------- /Source/Classes/MUServerViewController.h: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2011 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | #import 6 | 7 | typedef enum { 8 | MUServerViewControllerViewModeServer = 0, 9 | MUServerViewControllerViewModeChannel = 1, 10 | } MUServerViewControllerViewMode; 11 | 12 | @interface MUServerViewController : UITableViewController 13 | - (id) initWithServerModel:(MKServerModel *)serverModel; 14 | - (void) toggleMode; 15 | @end -------------------------------------------------------------------------------- /Source/Classes/MUServerCell.h: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2011 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | #import 6 | 7 | @class MUFavouriteServer; 8 | 9 | @interface MUServerCell : UITableViewCell 10 | + (NSString *) reuseIdentifier; 11 | - (void) populateFromDisplayName:(NSString *)displayName hostName:(NSString *)hostName port:(NSString *)port; 12 | - (void) populateFromFavouriteServer:(MUFavouriteServer *)favServ; 13 | @end 14 | -------------------------------------------------------------------------------- /Source/Classes/MUCertificateViewController.h: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2010 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | @class MKCertificate; 6 | 7 | @interface MUCertificateViewController : UITableViewController 8 | 9 | - (id) initWithPersistentRef:(NSData *)persistentRef; 10 | - (id) initWithCertificate:(MKCertificate *)cert; 11 | - (id) initWithCertificates:(NSArray *)certs; 12 | 13 | - (void) showDataForCertificate:(MKCertificate *)cert; 14 | - (void) updateCertificateDisplay; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /Source/main.m: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2010 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | @import UIKit; 6 | 7 | #import "Classes/MUApplicationDelegate.h" 8 | 9 | int main(int argc, char *argv[]) { 10 | NSString * appDelegateClassName; 11 | @autoreleasepool { 12 | // Setup code that might create autoreleased objects goes here. 13 | appDelegateClassName = NSStringFromClass([MUApplicationDelegate class]); 14 | } 15 | return UIApplicationMain(argc, argv, nil, appDelegateClassName); 16 | } 17 | -------------------------------------------------------------------------------- /Source/Classes/MUPublicServerList.h: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2010 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | @interface MUPublicServerListFetcher : NSObject 6 | - (void) attemptUpdate; 7 | @end 8 | 9 | @interface MUPublicServerList : NSObject 10 | - (void) parse; 11 | - (BOOL) isParsed; 12 | - (NSInteger) numberOfContinents; 13 | - (NSString *) continentNameAtIndex:(NSInteger)index; 14 | - (NSInteger) numberOfCountriesAtContinentIndex:(NSInteger)index; 15 | - (NSDictionary *) countryAtIndexPath:(NSIndexPath *)indexPath; 16 | @end 17 | -------------------------------------------------------------------------------- /Source/Classes/MUConnectionController.h: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2011 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | extern NSString *MUConnectionOpenedNotification; 6 | extern NSString *MUConnectionClosedNotification; 7 | 8 | @interface MUConnectionController : UIView 9 | + (MUConnectionController *) sharedController; 10 | - (void) connetToHostname:(NSString *)hostName port:(NSUInteger)port withUsername:(NSString *)userName andPassword:(NSString *)password withParentViewController:(UIViewController *)parentViewController; 11 | - (BOOL) isConnected; 12 | - (void) disconnectFromServer; 13 | @end 14 | -------------------------------------------------------------------------------- /Source/Classes/MUBackgroundView.m: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | #import "MUBackgroundView.h" 6 | #import "MUColor.h" 7 | #import "MUImage.h" 8 | 9 | @implementation MUBackgroundView 10 | 11 | + (UIView *) backgroundView { 12 | if (@available(iOS 7, *)) { 13 | UIView *view = [[UIView alloc] init]; 14 | [view setBackgroundColor:[MUColor backgroundViewiOS7Color]]; 15 | return view; 16 | } 17 | 18 | return [[UIImageView alloc] initWithImage:[MUImage imageNamed:@"BackgroundTextureBlackGradient"]]; 19 | } 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | on: [push, pull_request] 3 | env: 4 | buildDir: ${{ github.workspace }}/build/ 5 | 6 | jobs: 7 | build: 8 | runs-on: macos-15 # as of 2025-02-19 latest (aka 14) makes the build fail. yeah, no idea 9 | steps: 10 | - uses: actions/checkout@v4 11 | with: 12 | submodules: 'recursive' 13 | - uses: maxim-lobanov/setup-xcode@v1 14 | with: 15 | xcode-version: '16.2' 16 | - name: Build 17 | run: | 18 | gem install --verbose xcpretty 19 | set -o pipefail && xcodebuild -configuration Release -target "Mumble" CONFIGURATION_BUILD_DIR="${PWD}/__build__" CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO -sdk iphoneos | xcpretty 20 | -------------------------------------------------------------------------------- /Source/Classes/MUCertificateController.h: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2010 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | @import Foundation; 6 | #import 7 | 8 | @interface MUCertificateController : NSObject 9 | + (MKCertificate *) certificateWithPersistentRef:(NSData *)persistentRef; 10 | + (OSStatus) deleteCertificateWithPersistentRef:(NSData *)persistentRef; 11 | 12 | + (NSString *) fingerprintFromHexString:(NSString *)hexDigest; 13 | 14 | + (void) setDefaultCertificateByPersistentRef:(NSData *)persistentRef; 15 | + (MKCertificate *) defaultCertificate; 16 | 17 | + (NSArray *) persistentRefsForIdentities; 18 | @end 19 | -------------------------------------------------------------------------------- /Source/Classes/MUFavouriteServerEditViewController.h: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2010 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | #import "MUFavouriteServer.h" 6 | 7 | @interface MUFavouriteServerEditViewController : UITableViewController 8 | - (id) initInEditMode:(BOOL)editMode withContentOfFavouriteServer:(MUFavouriteServer *)favServ; 9 | - (id) init; 10 | 11 | #pragma mark Accessors 12 | 13 | - (MUFavouriteServer *) copyFavouriteFromContent; 14 | 15 | #pragma mark Target and action handlers 16 | 17 | - (void) setTarget:(id)target; 18 | - (id) target; 19 | 20 | - (void) setDoneAction:(SEL)action; 21 | - (SEL) doneAction; 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /Tests/MumbleTests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /Source/Classes/MUCertificateCell.h: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2010 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | @interface MUCertificateCell : UITableViewCell 6 | 7 | + (MUCertificateCell *) loadFromNib; 8 | 9 | - (void) setSubjectName:(NSString *)name; 10 | - (void) setEmail:(NSString *)email; 11 | - (void) setIssuerText:(NSString *)issuerText; 12 | - (void) setExpiryText:(NSString *)expiryText; 13 | 14 | - (BOOL) isIntermediate; 15 | - (void) setIsIntermediate:(BOOL)isIntermediate; 16 | 17 | - (BOOL) isExpired; 18 | - (void) setIsExpired:(BOOL)isExpired; 19 | 20 | - (BOOL) isCurrentCertificate; 21 | - (void) setIsCurrentCertificate:(BOOL)isSelected; 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /Source/Classes/MUServerCertificateTrustViewController.h: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2010 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | #import "MUCertificateViewController.h" 6 | 7 | @class MKConnection; 8 | @class MUServerCertificateTrustViewController; 9 | 10 | @protocol MUServerCertificateTrustViewControllerProtocol 11 | - (void) serverCertificateTrustViewControllerDidDismiss:(MUServerCertificateTrustViewController *)trustView; 12 | @end 13 | 14 | @interface MUServerCertificateTrustViewController : MUCertificateViewController 15 | - (id) delegate; 16 | - (void) setDelegate:(id)delegate; 17 | @end 18 | -------------------------------------------------------------------------------- /Source/Classes/MUFavouriteServer.h: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2010 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | @interface MUFavouriteServer : NSObject 6 | 7 | - (id) initWithDisplayName:(NSString *)displayName hostName:(NSString *)hostName port:(NSUInteger)port userName:(NSString *)userName password:(NSString *)passWord; 8 | - (id) init; 9 | 10 | @property (assign) NSInteger primaryKey; 11 | @property (copy) NSString *displayName; 12 | @property (copy) NSString *hostName; 13 | @property (assign) NSUInteger port; 14 | @property (copy) NSString *userName; 15 | @property (copy) NSString *password; 16 | 17 | - (BOOL) hasPrimaryKey; 18 | - (NSComparisonResult) compare:(MUFavouriteServer *)favServ; 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /Source/MainWindow.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /Source/Classes/MainWindow~iPad.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /Source/Classes/MUMessageRecipientViewController.h: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2012 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | #import 6 | 7 | @class MUMessageRecipientViewController; 8 | 9 | @protocol MUMessageRecipientViewControllerDelegate 10 | - (void) messageRecipientViewControllerDidSelectCurrentChannel:(MUMessageRecipientViewController *)viewCtrlr; 11 | - (void) messageRecipientViewController:(MUMessageRecipientViewController *)viewCtrlr didSelectUser:(MKUser *)user; 12 | - (void) messageRecipientViewController:(MUMessageRecipientViewController *)viewCtrlr didSelectChannel:(MKChannel *)channel; 13 | @end 14 | 15 | @interface MUMessageRecipientViewController : UITableViewController 16 | - (id) initWithServerModel:(MKServerModel *)serverModel; 17 | - (id) delegate; 18 | - (void) setDelegate:(id)delegate; 19 | @end 20 | -------------------------------------------------------------------------------- /Source/Classes/MUTextMessage.h: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2012 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | @interface MUTextMessage : NSObject { 6 | NSString *_heading; 7 | NSString *_msg; 8 | NSDate *_date; 9 | NSArray *_links; 10 | NSArray *_images; 11 | BOOL _self; 12 | } 13 | + (MUTextMessage *) textMessageWithHeading:(NSString *)heading 14 | andMessage:(NSString *)msg 15 | andEmbeddedLinks:(NSArray *)links 16 | andEmbeddedImages:(NSArray *)images 17 | andTimestampDate:(NSDate *)timestampDate 18 | isSentBySelf:(BOOL)sentBySelf; 19 | - (NSString *) heading; 20 | - (NSString *) message; 21 | - (NSDate *) date; 22 | - (NSArray *) embeddedLinks; 23 | - (NSArray *) embeddedImages; 24 | - (NSInteger) numberOfAttachments; 25 | - (BOOL) hasAttachments; 26 | - (BOOL) isSentBySelf; 27 | @end 28 | -------------------------------------------------------------------------------- /Source/Classes/MUTableViewHeaderLabel.m: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2011 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | #import "MUTableViewHeaderLabel.h" 6 | 7 | @implementation MUTableViewHeaderLabel 8 | 9 | - (id) init { 10 | if ((self = [super init])) { 11 | self.font = [UIFont boldSystemFontOfSize:18.0f]; 12 | self.textColor = [UIColor whiteColor]; 13 | if (@available(iOS 7, *)) { 14 | // Don't use shadows on iOS 7 or greater. 15 | } else { 16 | self.shadowColor = [UIColor darkGrayColor]; 17 | self.shadowOffset = CGSizeMake(1.5f, 1.5f); 18 | } 19 | self.backgroundColor = [UIColor clearColor]; 20 | self.textAlignment = NSTextAlignmentCenter; 21 | } 22 | return self; 23 | } 24 | 25 | + (CGFloat) defaultHeaderHeight { 26 | return 44.0f; 27 | } 28 | 29 | + (MUTableViewHeaderLabel *) labelWithText:(NSString *)text { 30 | MUTableViewHeaderLabel *label = [[MUTableViewHeaderLabel alloc] init]; 31 | label.text = text; 32 | return label; 33 | } 34 | 35 | @end 36 | -------------------------------------------------------------------------------- /Source/Classes/MUServerTableViewCell.m: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | #import "MUServerTableViewCell.h" 6 | 7 | @implementation MUServerTableViewCell 8 | 9 | - (id) initWithReuseIdentifier:(NSString *)reuseIdentifier { 10 | if ((self = [super initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuseIdentifier])) { 11 | // ... 12 | } 13 | return self; 14 | } 15 | 16 | - (void) layoutSubviews { 17 | [super layoutSubviews]; 18 | 19 | self.separatorInset = UIEdgeInsetsMake(0, 0, 0, 0); 20 | 21 | self.imageView.frame = CGRectMake( 22 | 8 + self.indentationLevel * self.indentationWidth, 23 | CGRectGetMinY(self.imageView.frame), 24 | CGRectGetWidth(self.imageView.frame), 25 | CGRectGetHeight(self.imageView.frame) 26 | ); 27 | 28 | self.textLabel.frame = CGRectMake( 29 | CGRectGetMinX(self.imageView.frame) + 40, 30 | CGRectGetMinY(self.textLabel.frame), 31 | CGRectGetWidth(self.frame) - (CGRectGetMinX(self.imageView.frame) + 60), 32 | CGRectGetHeight(self.textLabel.frame) 33 | ); 34 | } 35 | 36 | @end 37 | -------------------------------------------------------------------------------- /Source/Classes/MUColor.m: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2011 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | #import "MUColor.h" 6 | 7 | @implementation MUColor 8 | 9 | + (UIColor *) selectedTextColor { 10 | // #5d5d5d 11 | return [UIColor colorWithRed:0x5d/255.0f green:0x5d/255.0f blue:0x5d/255.0f alpha:1.0f]; 12 | } 13 | 14 | + (UIColor *) goodPingColor { 15 | // #609a4b 16 | return [UIColor colorWithRed:0x60/255.0f green:0x9a/255.0f blue:0x4b/255.0f alpha:1.0f]; 17 | } 18 | 19 | + (UIColor *) mediumPingColor { 20 | // #F2DE69 21 | return [UIColor colorWithRed:0xf2/255.0f green:0xde/255.0f blue:0x69/255.0f alpha:1.0f]; 22 | } 23 | 24 | + (UIColor *) badPingColor { 25 | // #D14D54 26 | return [UIColor colorWithRed:0xd1/255.0f green:0x4d/255.0f blue:0x54/255.0f alpha:1.0f]; 27 | } 28 | 29 | + (UIColor *) userCountColor { 30 | return [UIColor darkGrayColor]; 31 | } 32 | 33 | + (UIColor *) verifiedCertificateChainColor { 34 | return [UIColor colorWithRed:0xdf/255.0f green:1.0f blue:0xdf/255.0f alpha:1.0f]; 35 | } 36 | 37 | + (UIColor *) backgroundViewiOS7Color { 38 | return [UIColor colorWithRed:0x1C/255.0f green:0x1C/255.0f blue:0x1C/255.0f alpha:1.0f]; 39 | } 40 | 41 | @end 42 | -------------------------------------------------------------------------------- /Source/Classes/MUAudioBarViewCell.m: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2011 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | #import "MUAudioBarView.h" 6 | #import "MUAudioBarViewCell.h" 7 | 8 | @interface MUAudioBarViewCell () { 9 | MUAudioBarView *_audioBarView; 10 | } 11 | @end 12 | 13 | @implementation MUAudioBarViewCell 14 | 15 | - (id) initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { 16 | if ((self = [super initWithStyle:style reuseIdentifier:reuseIdentifier])) { 17 | MUAudioBarView *audioBarView = [[MUAudioBarView alloc] initWithFrame:self.bounds]; 18 | [audioBarView setBelow:0.4f]; 19 | [audioBarView setAbove:0.6f]; 20 | [self setBackgroundView:audioBarView]; 21 | // Round the corners on anything but iOS 7 and greater. 22 | if (@available(iOS 7, *)) { 23 | self.backgroundView.layer.masksToBounds = NO; 24 | self.backgroundView.layer.cornerRadius = 0.0f; 25 | } else { 26 | self.backgroundView.layer.masksToBounds = YES; 27 | self.backgroundView.layer.cornerRadius = 8.0f; 28 | } 29 | self.backgroundColor = [UIColor clearColor]; 30 | } 31 | return self; 32 | } 33 | 34 | @end 35 | -------------------------------------------------------------------------------- /Source/Classes/MUDatabase.h: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2011 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | #import 6 | 7 | @class MUFavouriteServer; 8 | @class Identity; 9 | 10 | @interface MUDatabase : NSObject 11 | 12 | + (void) initializeDatabase; 13 | + (void) teardown; 14 | 15 | // FavouriteServer 16 | + (void) storeFavourite:(MUFavouriteServer *)favServ; 17 | + (void) deleteFavourite:(MUFavouriteServer *)favServ; 18 | + (void) storeFavourites:(NSArray *)favourites; 19 | + (NSMutableArray *) fetchAllFavourites; 20 | 21 | // Cert verification 22 | + (void) storeDigest:(NSString *)hash forServerWithHostname:(NSString *)hostname port:(NSInteger)port; 23 | + (NSString *) digestForServerWithHostname:(NSString *)hostname port:(NSInteger)port; 24 | 25 | // Username-rememberer 26 | + (void) storeUsername:(NSString *)username forServerWithHostname:(NSString *)hostname port:(NSInteger)port; 27 | + (NSString *) usernameForServerWithHostname:(NSString *)hostname port:(NSInteger)port; 28 | 29 | // Access tokens 30 | + (void) storeAccessTokens:(NSArray *)tokens forServerWithHostname:(NSString *)hostname port:(NSInteger)port; 31 | + (NSArray *) accessTokensForServerWithHostname:(NSString *)hostname port:(NSInteger)port; 32 | 33 | @end 34 | -------------------------------------------------------------------------------- /Source/Classes/MUMessageBubbleTableViewCell.h: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2012 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | @class MUMessageBubbleTableViewCell; 6 | 7 | @protocol MUMessageBubbleTableViewCellDelegate 8 | - (void) messageBubbleTableViewCellRequestedAttachmentViewer:(MUMessageBubbleTableViewCell *)cell; 9 | - (void) messageBubbleTableViewCellRequestedDeletion:(MUMessageBubbleTableViewCell *)cell; 10 | - (void) messageBubbleTableViewCellRequestedCopy:(MUMessageBubbleTableViewCell *)cell; 11 | @end 12 | 13 | @interface MUMessageBubbleTableViewCell : UITableViewCell 14 | + (CGFloat) heightForCellWithHeading:(NSString *)heading message:(NSString *)msg images:(NSArray *)images footer:(NSString *)footer date:(NSDate *)date; 15 | 16 | - (id) initWithReuseIdentifier:(NSString *)reuseIdentifier; 17 | - (void) setHeading:(NSString *)heading; 18 | - (void) setMessage:(NSString *)msg; 19 | - (void) setShownImages:(NSArray *)shownImages; 20 | - (void) setFooter:(NSString *)footer; 21 | - (void) setDate:(NSDate *)date; 22 | - (void) setRightSide:(BOOL)rightSide; 23 | - (void) setSelected:(BOOL)selected; 24 | 25 | - (id) delegate; 26 | - (void) setDelegate:(id)delegate; 27 | @end 28 | -------------------------------------------------------------------------------- /Source/Classes/MULegalViewController.m: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2011 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | #import "MULegalViewController.h" 6 | 7 | @import WebKit.WKWebView; 8 | 9 | @interface MULegalViewController () { 10 | IBOutlet WKWebView *_webView; 11 | } 12 | @end 13 | 14 | @implementation MULegalViewController 15 | 16 | - (id) init { 17 | if ((self = [super initWithNibName:@"MULegalViewController" bundle:nil])) { 18 | // ... 19 | } 20 | return self; 21 | } 22 | 23 | - (void) viewWillAppear:(BOOL)animated { 24 | self.navigationItem.title = NSLocalizedString(@"Legal", nil); 25 | 26 | UIBarButtonItem *done = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(doneButtonClicked:)]; 27 | self.navigationItem.rightBarButtonItem = done; 28 | 29 | NSData *html = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Legal" ofType:@"html"]]; 30 | [_webView loadData:html MIMEType:@"text/html" characterEncodingName:@"utf-8" baseURL:[NSURL URLWithString:@"http://localhost"]]; 31 | } 32 | 33 | - (void) doneButtonClicked:(id)sender { 34 | [self dismissViewControllerAnimated:YES completion:nil]; 35 | } 36 | 37 | @end 38 | -------------------------------------------------------------------------------- /Source/Classes/MUDataURL.m: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2012 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | #import "MUDataURL.h" 6 | 7 | @implementation MUDataURL 8 | 9 | // todo(mkrautz): Redo this with our own internal scanning and base64 decoding 10 | // to get rid of the string copying. 11 | + (NSData *) dataFromDataURL:(NSString *)dataURL { 12 | // Read: data:;, 13 | // Expect encoding = base64 14 | 15 | if (![dataURL hasPrefix:@"data:"]) 16 | return nil; 17 | NSString *mimeStr = [dataURL substringFromIndex:5]; 18 | NSRange r = [mimeStr rangeOfString:@";"]; 19 | if (r.location == NSNotFound) 20 | return nil; 21 | NSString *mimeType = [mimeStr substringToIndex:r.location]; 22 | (void) mimeType; 23 | r.location += 1; 24 | r.length = 7; 25 | if ([mimeStr length] < r.location+r.length) 26 | return nil; 27 | if (![[mimeStr substringWithRange:r] isEqualToString:@"base64,"]) 28 | return nil; 29 | 30 | NSString *base64data = [mimeStr substringFromIndex:r.location+r.length]; 31 | base64data = [base64data stringByRemovingPercentEncoding]; 32 | base64data = [base64data stringByReplacingOccurrencesOfString:@" " withString:@""]; 33 | return [[NSData alloc] initWithBase64EncodedString:base64data options:0]; 34 | } 35 | 36 | + (UIImage *) imageFromDataURL:(NSString *)dataURL { 37 | return [UIImage imageWithData:[MUDataURL dataFromDataURL:dataURL]]; 38 | } 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /Source/Classes/MUPopoverBackgroundView.m: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2012 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | #import "MUPopoverBackgroundView.h" 6 | 7 | @interface MUPopoverBackgroundView () { 8 | UIImageView *_imgView; 9 | } 10 | @end 11 | 12 | @implementation MUPopoverBackgroundView 13 | 14 | - (id) initWithFrame:(CGRect)frame { 15 | if ((self = [super initWithFrame:frame])) { 16 | UIEdgeInsets insets = UIEdgeInsetsMake(41.0f, 47.0f, 10.0f, 10.0f); 17 | UIImage *img = [UIImage imageNamed:@"_UIPopoverViewBlackBackgroundArrowUp"]; 18 | UIImage *stretchableImg = [img resizableImageWithCapInsets:insets]; 19 | 20 | _imgView = [[UIImageView alloc] initWithImage:stretchableImg]; 21 | [self addSubview:_imgView]; 22 | } 23 | return self; 24 | } 25 | 26 | - (UIPopoverArrowDirection) arrowDirection { 27 | return UIPopoverArrowDirectionUp; 28 | } 29 | 30 | - (void) setArrowDirection:(UIPopoverArrowDirection)arrowDirection { 31 | } 32 | 33 | - (CGFloat) arrowOffset { 34 | return 0.0f; 35 | } 36 | 37 | - (void) setArrowOffset:(CGFloat)arrowOffset { 38 | } 39 | 40 | + (CGFloat) arrowBase { 41 | return 35.0f; 42 | } 43 | 44 | + (CGFloat) arrowHeight { 45 | return 19.0f; 46 | } 47 | 48 | + (UIEdgeInsets) contentViewInsets { 49 | return UIEdgeInsetsMake(8.0f, 11.0f, 11.0f, 11.0f); 50 | } 51 | 52 | - (void) layoutSubviews { 53 | [super layoutSubviews]; 54 | _imgView.frame = self.frame; 55 | } 56 | 57 | @end 58 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2009-2014 The 'Mumble for iOS' Developers 2 | 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions 7 | are met: 8 | 9 | - Redistributions of source code must retain the above copyright notice, 10 | this list of conditions and the following disclaimer. 11 | - Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | - Neither the name of the 'Mumble for iOS' Developers nor the names of its 15 | contributors may be used to endorse or promote products derived from this 16 | software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR 22 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 23 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 25 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 26 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 27 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | Mumble for iOS (iPhone, iPod touch and iPad) 2 | ============================================ 3 | 4 | **Note:** This repo and the app for iOS are unmaintained. 5 | If you are interested in taking over development of the app, write a comment in [#129](https://github.com/mumble-voip/mumble-iphoneos/issues/129). 6 | 7 | 8 | This is the source code of Mumble (a voice chat application) for iOS-based devices. 9 | 10 | The [desktop version](https://github.com/mumble-voip/mumble) of Mumble runs on Windows, Mac OS X, Linux 11 | and various other Unix-like systems. 12 | 13 | Visit our website at: 14 | 15 | 16 | Building it 17 | =========== 18 | 19 | To build this you need Xcode 16 and the latest iOS SDK from Apple. 20 | 21 | The easiest way to get a working source tree is to check out 22 | the mumble-iphoneos repository recursively (his will recursively 23 | fetch all submodules), because there are quite a few submodules. 24 | 25 | To fetch the repository: 26 | 27 | $ git clone --recursive http://github.com/mumble-voip/mumble-iphoneos.git 28 | 29 | Once this is done, you should be able to open up the Xcode 30 | project file for Mumble (Mumble.xcodeproj) in the root of 31 | the source tree and hit Cmd-B to build! 32 | 33 | Extra tips for advanced users 34 | ============================= 35 | 36 | When launching Mumble.xcodeproj for the first time, you're recommended to 37 | remove all schemes but the Mumble one. Xcode will automatically populate 38 | it with the schemes of all .xcodeprojs in the workspace. 39 | 40 | Schemes can be configured using the dropdown box right of the start and stop 41 | buttons in the default Xcode 4 UI. 42 | 43 | We also recommend you to edit the default scheme for the Mumble target 44 | and change the Archive configuration to BetaDist, and the Test configuration 45 | to Release (debug builds pretty slow for devices, but for the Simulator, they're 46 | OK!) 47 | -------------------------------------------------------------------------------- /Source/Classes/MUServerCertificateTrustViewController.m: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2010 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | #import 6 | #import 7 | 8 | #import "MUServerCertificateTrustViewController.h" 9 | #import "MUDatabase.h" 10 | 11 | @interface MUServerCertificateTrustViewController () { 12 | NSArray *_certChain; 13 | id _delegate; 14 | } 15 | @end 16 | 17 | // This is the modal view controller that's shown to the user 18 | // when iOS doesn't trsut the certificate chain of the server, 19 | // and the user picks "Show Certificates" 20 | 21 | @implementation MUServerCertificateTrustViewController 22 | 23 | - (void) setDelegate:(id)delegate { 24 | _delegate = delegate; 25 | } 26 | 27 | - (id) delegate { 28 | return _delegate; 29 | } 30 | 31 | - (void) viewWillAppear:(BOOL)animated { 32 | [super viewWillAppear:animated]; 33 | 34 | UIBarButtonItem *dismissButton = [[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(@"Dismiss", nil) 35 | style:UIBarButtonItemStylePlain 36 | target:self 37 | action:@selector(dismissClicked:)]; 38 | self.navigationItem.leftBarButtonItem = dismissButton; 39 | } 40 | 41 | #pragma mark - 42 | #pragma mark Actions 43 | 44 | - (void) dismissClicked:(id)sender { 45 | [self dismissViewControllerAnimated:YES completion:nil]; 46 | [_delegate serverCertificateTrustViewControllerDidDismiss:self]; 47 | } 48 | 49 | @end 50 | -------------------------------------------------------------------------------- /Source/Classes/MUUserStateAcessoryView.m: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2011 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | #import "MUUserStateAcessoryView.h" 6 | 7 | #import 8 | 9 | @implementation MUUserStateAcessoryView 10 | 11 | + (UIView *) viewForUser:(MKUser *)user { 12 | const CGFloat iconHeight = 24.0f; 13 | const CGFloat iconWidth = 28.0f; 14 | 15 | NSMutableArray *states = [[NSMutableArray alloc] init]; 16 | if ([user isAuthenticated]) 17 | [states addObject:@"authenticated"]; 18 | if ([user isSelfDeafened]) 19 | [states addObject:@"deafened_self"]; 20 | if ([user isSelfMuted]) 21 | [states addObject:@"muted_self"]; 22 | if ([user isMuted]) 23 | [states addObject:@"muted_server"]; 24 | if ([user isDeafened]) 25 | [states addObject:@"deafened_server"]; 26 | if ([user isLocalMuted]) 27 | [states addObject:@"muted_local"]; 28 | if ([user isSuppressed]) 29 | [states addObject:@"muted_suppressed"]; 30 | if ([user isPrioritySpeaker]) 31 | [states addObject:@"priorityspeaker"]; 32 | 33 | CGFloat widthOffset = [states count] * iconWidth; 34 | UIView *stateView = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, widthOffset, iconHeight)]; 35 | for (NSString *imageName in states) { 36 | UIImage *img = [UIImage imageNamed:imageName]; 37 | UIImageView *imgView = [[UIImageView alloc] initWithImage:img]; 38 | CGFloat ypos = (iconHeight - img.size.height)/2.0f; 39 | CGFloat xpos = (iconWidth - img.size.width)/2.0f; 40 | widthOffset -= iconWidth - xpos; 41 | imgView.frame = CGRectMake(ceilf(widthOffset), ceilf(ypos), img.size.width, img.size.height); 42 | [stateView addSubview:imgView]; 43 | } 44 | 45 | return stateView; 46 | } 47 | 48 | @end 49 | -------------------------------------------------------------------------------- /Source/Classes/MUFavouriteServer.m: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2010 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | #import "MUFavouriteServer.h" 6 | #import "MUDatabase.h" 7 | 8 | @interface MUFavouriteServer () { 9 | NSInteger _pkey; 10 | NSString *_displayName; 11 | NSString *_hostName; 12 | NSUInteger _port; 13 | NSString *_userName; 14 | NSString *_password; 15 | } 16 | @end 17 | 18 | @implementation MUFavouriteServer 19 | 20 | @synthesize primaryKey = _pkey; 21 | @synthesize displayName = _displayName; 22 | @synthesize hostName = _hostName; 23 | @synthesize port = _port; 24 | @synthesize userName = _userName; 25 | @synthesize password = _password; 26 | 27 | - (id) initWithDisplayName:(NSString *)displayName hostName:(NSString *)hostName port:(NSUInteger)port userName:(NSString *)userName password:(NSString *)passWord { 28 | self = [super init]; 29 | if (self == nil) 30 | return nil; 31 | 32 | _pkey = -1; 33 | _displayName = [displayName copy]; 34 | _hostName = [hostName copy]; 35 | _port = port; 36 | _userName = [userName copy]; 37 | _password = [passWord copy]; 38 | 39 | return self; 40 | } 41 | 42 | - (id) init { 43 | return [self initWithDisplayName:nil hostName:nil port:0 userName:nil password:nil]; 44 | } 45 | 46 | - (id) copyWithZone:(NSZone *)zone { 47 | MUFavouriteServer *favServ = [[MUFavouriteServer alloc] initWithDisplayName:_displayName hostName:_hostName port:_port userName:_userName password:_password]; 48 | if ([self hasPrimaryKey]) 49 | [favServ setPrimaryKey:[self primaryKey]]; 50 | return favServ; 51 | } 52 | 53 | - (BOOL) hasPrimaryKey { 54 | return _pkey != -1; 55 | } 56 | 57 | - (NSComparisonResult) compare:(MUFavouriteServer *)favServ { 58 | return [_displayName caseInsensitiveCompare:[favServ displayName]]; 59 | } 60 | 61 | @end 62 | -------------------------------------------------------------------------------- /Source/Classes/MUTextMessage.m: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2012 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | #import "MUTextMessage.h" 6 | 7 | @interface MUTextMessage () { 8 | } 9 | - (id) initWithHeading:(NSString *)heading andMessage:(NSString *)msg andDate:(NSDate *)date andEmbeddedLinks:(NSArray *)links andEmbeddedImages:(NSArray *)images andTimestampDate:(NSDate *)date andSentBySelf:(BOOL)sentBySelf; 10 | @end 11 | 12 | @implementation MUTextMessage 13 | 14 | - (id) initWithHeading:(NSString *)heading andMessage:(NSString *)msg andDate:(NSDate *)date andEmbeddedLinks:(NSArray *)links andEmbeddedImages:(NSArray *)images andTimestampDate:(NSDate *)timestampDate andSentBySelf:(BOOL)sentBySelf { 15 | if ((self = [super init])) { 16 | _heading = heading; 17 | _msg = msg; 18 | _date = date; 19 | _self = sentBySelf; 20 | _links = links; 21 | _images = images; 22 | } 23 | return self; 24 | } 25 | 26 | - (NSString *) heading { 27 | return _heading; 28 | } 29 | 30 | - (NSString *) message { 31 | return _msg; 32 | } 33 | 34 | - (NSDate *) date { 35 | return _date; 36 | } 37 | 38 | - (NSInteger) numberOfAttachments { 39 | return [_links count] + [_images count]; 40 | } 41 | 42 | - (BOOL) hasAttachments { 43 | return [self numberOfAttachments] > 0; 44 | } 45 | 46 | - (NSArray *) embeddedLinks { 47 | return _links; 48 | } 49 | 50 | - (NSArray *) embeddedImages { 51 | return _images; 52 | } 53 | 54 | - (BOOL) isSentBySelf { 55 | return _self; 56 | } 57 | 58 | + (MUTextMessage *) textMessageWithHeading:(NSString *)heading andMessage:(NSString *)msg andEmbeddedLinks:(NSArray *)links andEmbeddedImages:(NSArray *)images andTimestampDate:(NSDate *)timestampDate isSentBySelf:(BOOL)sentBySelf { 59 | return [[MUTextMessage alloc] initWithHeading:heading andMessage:msg andDate:timestampDate andEmbeddedLinks:links andEmbeddedImages:images andTimestampDate:timestampDate andSentBySelf:sentBySelf]; 60 | } 61 | 62 | @end 63 | -------------------------------------------------------------------------------- /BuildConfig/Base.xcconfig: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | ARCHS = arm64 6 | SDKROOT = iphoneos 7 | 8 | MACOSX_DEPLOYMENT_TARGET = 10.13 9 | IPHONEOS_DEPLOYMENT_TARGET = 12.0 10 | 11 | CODE_SIGN_IDENTITY[sdk=iphoneos*] = iPhone Developer 12 | 13 | TARGETED_DEVICE_FAMILY = 1 // iPhone 14 | 15 | ALWAYS_SEARCH_USER_PATHS = NO 16 | USER_HEADER_SEARCH_PATHS = 17 | HEADER_SEARCH_PATHS = "${PROJECT_DIR}/MumbleKit/src/" "${PROJECT_DIR}/Dependencies/MKNumberBadgeView/" 18 | FRAMEWORK_SEARCH_PATHS = 19 | 20 | OTHER_CFLAGS = -DNS_BLOCK_ASSERTIONS=1 21 | 22 | GCC_WARN_ABOUT_RETURN_TYPE = YES 23 | GCC_WARN_UNUSED_VARIABLE = YES 24 | 25 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES 26 | CLANG_ENABLE_OBJC_WEAK = YES 27 | CLANG_WARN_BOOL_CONVERSION = YES 28 | CLANG_WARN_CONSTANT_CONVERSION = YES 29 | CLANG_WARN_EMPTY_BODY = YES 30 | CLANG_WARN_ENUM_CONVERSION = YES 31 | CLANG_WARN_INFINITE_RECURSION = YES 32 | CLANG_WARN_INT_CONVERSION = YES 33 | CLANG_WARN_SUSPICIOUS_MOVE = YES 34 | CLANG_WARN_UNREACHABLE_CODE = YES 35 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES 36 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES 37 | CLANG_WARN_COMMA = YES 38 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES 39 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES 40 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES 41 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES 42 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES 43 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES 44 | CLANG_WARN_STRICT_PROTOTYPES = YES 45 | ENABLE_STRICT_OBJC_MSGSEND = YES 46 | ENABLE_USER_SCRIPT_SANDBOXING = YES 47 | GCC_NO_COMMON_BLOCKS = YES 48 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES 49 | GCC_WARN_UNDECLARED_SELECTOR = YES 50 | GCC_WARN_UNINITIALIZED_AUTOS = YES 51 | GCC_WARN_UNUSED_FUNCTION = YES 52 | 53 | INFOPLIST_FILE = Source/Info.plist 54 | 55 | GCC_PRECOMPILE_PREFIX_HEADER = YES 56 | GCC_PREFIX_HEADER = Source/Mumble.pch 57 | 58 | VALIDATE_PRODUCT = YES 59 | 60 | OTHER_LDFLAGS = -all_load -ObjC -lc++ 61 | 62 | ENABLE_BITCODE = NO 63 | 64 | PRODUCT_NAME = Mumble 65 | PRODUCT_BUNDLE_IDENTIFIER = info.mumble.${PRODUCT_NAME:rfc1034identifier} 66 | -------------------------------------------------------------------------------- /Source/Classes/MUHorizontalFlipTransitionDelegate.m: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | #import "MUHorizontalFlipTransitionDelegate.h" 6 | 7 | @implementation MUHorizontalFlipTransitionDelegate 8 | 9 | - (id) animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source { 10 | return (id) self; 11 | } 12 | 13 | - (id) animationControllerForDismissedController:(UIViewController *)dismissed { 14 | return (id)self; 15 | } 16 | 17 | - (NSTimeInterval) transitionDuration:(id)transitionContext { 18 | return 0.7f; 19 | } 20 | 21 | - (void) animateTransition:(id)transitionContext { 22 | UIView *containerView = [transitionContext containerView]; 23 | 24 | UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; 25 | [containerView addSubview:fromViewController.view]; 26 | 27 | UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; 28 | [containerView addSubview:toViewController.view]; 29 | 30 | UIViewAnimationOptions animationOption; 31 | if ([toViewController.presentedViewController isEqual:fromViewController]) { 32 | animationOption = UIViewAnimationOptionTransitionFlipFromLeft; 33 | } else { 34 | animationOption = UIViewAnimationOptionTransitionFlipFromRight; 35 | } 36 | 37 | [UIView transitionFromView:fromViewController.view 38 | toView:toViewController.view 39 | duration:[self transitionDuration:transitionContext] 40 | options:animationOption 41 | completion:^(BOOL finished) { 42 | [transitionContext completeTransition:YES]; 43 | }]; 44 | } 45 | 46 | @end 47 | -------------------------------------------------------------------------------- /Source/Classes/MULegalViewController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /Source/Classes/MUCertificateCell.m: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2010 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | #import "MUCertificateCell.h" 6 | #import "MUColor.h" 7 | 8 | @interface MUCertificateCell () { 9 | IBOutlet UIImageView *_certImage; 10 | IBOutlet UILabel *_nameLabel; 11 | IBOutlet UILabel *_emailLabel; 12 | IBOutlet UILabel *_issuerLabel; 13 | IBOutlet UILabel *_expiryLabel; 14 | BOOL _isCurrentCert; 15 | BOOL _isExpired; 16 | BOOL _isIntermediate; 17 | } 18 | @end 19 | 20 | @implementation MUCertificateCell 21 | 22 | + (MUCertificateCell *) loadFromNib { 23 | NSArray *array = [[NSBundle mainBundle] loadNibNamed:@"MUCertificateCell" owner:self options:nil]; 24 | return [array objectAtIndex:0]; 25 | } 26 | 27 | - (void) setSubjectName:(NSString *)name { 28 | _nameLabel.text = name; 29 | } 30 | 31 | - (void) setEmail:(NSString *)email { 32 | _emailLabel.text = email; 33 | } 34 | 35 | - (void) setIssuerText:(NSString *)issuerText { 36 | _issuerLabel.text = issuerText; 37 | } 38 | 39 | - (void) setExpiryText:(NSString *)expiryText { 40 | _expiryLabel.text = expiryText; 41 | } 42 | 43 | - (void) setIsIntermediate:(BOOL)isIntermediate { 44 | _isIntermediate = isIntermediate; 45 | if (_isIntermediate) { 46 | [_certImage setImage:[UIImage imageNamed:@"certificatecell-intermediate"]]; 47 | } else { 48 | [_certImage setImage:[UIImage imageNamed:@"certificatecell"]]; 49 | } 50 | } 51 | 52 | - (BOOL) isIntermediate { 53 | return _isIntermediate; 54 | } 55 | 56 | - (void) setIsExpired:(BOOL)isExpired { 57 | _isExpired = isExpired; 58 | _expiryLabel.textColor = [UIColor redColor]; 59 | } 60 | 61 | - (BOOL) isExpired { 62 | return _isExpired; 63 | } 64 | 65 | - (void) setIsCurrentCertificate:(BOOL)isCurrent { 66 | _isCurrentCert = isCurrent; 67 | if (isCurrent) { 68 | [_certImage setImage:[UIImage imageNamed:@"certificatecell-selected"]]; 69 | [_nameLabel setTextColor:[MUColor selectedTextColor]]; 70 | [_emailLabel setTextColor:[MUColor selectedTextColor]]; 71 | } else { 72 | if (_isIntermediate) { 73 | [_certImage setImage:[UIImage imageNamed:@"certificatecell-intermediate"]]; 74 | } else { 75 | [_certImage setImage:[UIImage imageNamed:@"certificatecell"]]; 76 | } 77 | [_nameLabel setTextColor:[UIColor blackColor]]; 78 | [_emailLabel setTextColor:[UIColor blackColor]]; 79 | } 80 | } 81 | 82 | - (BOOL) isCurrentCertificate { 83 | return _isCurrentCert; 84 | } 85 | 86 | @end 87 | -------------------------------------------------------------------------------- /Source/Classes/MUCertificateCreationProgressView.m: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2010 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | #import "MUCertificateCreationProgressView.h" 6 | #import "MUImage.h" 7 | #import "MUColor.h" 8 | #import "MUBackgroundView.h" 9 | 10 | @interface MUCertificateCreationProgressView () { 11 | IBOutlet UIImageView *_backgroundImage; 12 | IBOutlet UIActivityIndicatorView *_activityIndicator; 13 | IBOutlet UILabel *_nameLabel; 14 | IBOutlet UILabel *_emailLabel; 15 | IBOutlet UILabel *_pleaseWaitLabel; 16 | 17 | NSString *_identityName; 18 | NSString *_emailAddress; 19 | id _delegate; 20 | } 21 | @end 22 | 23 | @implementation MUCertificateCreationProgressView 24 | 25 | - (id) initWithName:(NSString *)name email:(NSString *)email { 26 | if (self = [super initWithNibName:@"MUCertificateCreationProgressView" bundle:nil]) { 27 | _identityName = name; 28 | _emailAddress = email; 29 | 30 | if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) { 31 | [self.view setBackgroundColor:[UIColor groupTableViewBackgroundColor]]; 32 | } 33 | } 34 | return self; 35 | } 36 | 37 | - (void) viewDidLoad { 38 | // fixme(mkrautz): This is esentially what a MUBackgroundView does. 39 | if (@available(iOS 7, *)) { 40 | _backgroundImage.backgroundColor = [MUColor backgroundViewiOS7Color]; 41 | } else { 42 | _backgroundImage.image = [MUImage imageNamed:@"BackgroundTextureBlackGradient"]; 43 | } 44 | 45 | // Unset text shadows for iOS 7. 46 | if (@available(iOS 7, *)) { 47 | _nameLabel.shadowOffset = CGSizeZero; 48 | _emailLabel.shadowOffset = CGSizeZero; 49 | _pleaseWaitLabel.shadowOffset = CGSizeZero; 50 | } 51 | } 52 | 53 | - (void) viewWillAppear:(BOOL)animated { 54 | [[self navigationItem] setTitle:NSLocalizedString(@"Generating Certificate", @"Title for certificate generator view controller")]; 55 | [[self navigationItem] setHidesBackButton:YES]; 56 | 57 | [_nameLabel setText:_identityName]; 58 | 59 | if (_emailAddress != nil && _emailAddress.length > 0) { 60 | [_emailLabel setText:[NSString stringWithFormat:@"<%@>", _emailAddress]]; 61 | } else { 62 | [_emailLabel setText:nil]; 63 | } 64 | 65 | [_pleaseWaitLabel setText:NSLocalizedString(@"Please Wait...", @"'Please Wait' text for certificate generation")]; 66 | [_activityIndicator startAnimating]; 67 | } 68 | 69 | @end 70 | -------------------------------------------------------------------------------- /Source/Classes/MUTextMessageProcessor.m: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | #import "MUTextMessageProcessor.h" 6 | 7 | @implementation MUTextMessageProcessor 8 | 9 | // processedHTMLFromPlainTextMessage converts the plain text-formatted text message 10 | // in plain to a HTML message that can be sent to another Mumble client. 11 | + (NSString *) processedHTMLFromPlainTextMessage:(NSString *)plain { 12 | // First, ensure that the plain text string doesn't already contain HTML tags. 13 | // Replace > with < and < with > 14 | NSString *str = [plain stringByReplacingOccurrencesOfString:@"<" withString:@"<"]; 15 | str = [str stringByReplacingOccurrencesOfString:@">" withString:@">"]; 16 | 17 | // Use NSDataDetectors to detect any links in the message and 18 | // automatically convert them to -tags. 19 | NSError *err = nil; 20 | NSDataDetector *linkDetector = [NSDataDetector dataDetectorWithTypes:(NSTextCheckingTypeLink &NSTextCheckingAllSystemTypes) error:&err]; 21 | if (err == nil && linkDetector != nil) { 22 | NSMutableString *output = [NSMutableString stringWithCapacity:[str length]*2]; 23 | NSArray *matches = [linkDetector matchesInString:str options:0 range:NSMakeRange(0, [str length])]; 24 | NSUInteger lastIndex = 0; 25 | 26 | [output appendString:@"

"]; 27 | 28 | for (NSTextCheckingResult *match in matches) { 29 | NSRange urlRange = [match range]; 30 | NSRange beforeUrlRange = NSMakeRange(lastIndex, urlRange.location-lastIndex); 31 | 32 | // Extract the string that is in front of the URL part and output 33 | // it to 'output'. 34 | NSString *beforeURL = [str substringWithRange:beforeUrlRange]; 35 | if (beforeURL == nil) { 36 | return nil; 37 | } 38 | [output appendString:beforeURL]; 39 | 40 | // Extract the URL and format it as a HTML a-tag. 41 | NSString *url = [str substringWithRange:urlRange]; 42 | NSString *anchor = [NSString stringWithFormat:@"%@", url, url]; 43 | if (anchor == nil) { 44 | return nil; 45 | } 46 | [output appendString:anchor]; 47 | 48 | // Update the lastIndex to keep track of 49 | lastIndex = urlRange.location + urlRange.length; 50 | } 51 | 52 | // Ensure that any remaining parts of the string are added to the output buffer. 53 | NSString *lastChunk = [str substringWithRange:NSMakeRange(lastIndex, [str length]-lastIndex)]; 54 | if (lastChunk == nil) { 55 | return nil; 56 | } 57 | [output appendString:lastChunk]; 58 | 59 | [output appendString:@"

"]; 60 | 61 | return output; 62 | } 63 | 64 | return [NSString stringWithFormat:@"

%@

", str]; 65 | } 66 | 67 | @end 68 | -------------------------------------------------------------------------------- /Source/Classes/MUImage.m: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2012 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | #import "MUImage.h" 6 | 7 | @implementation MUImage 8 | 9 | + (UIImage *) tableViewCellImageFromImage:(UIImage *)srcImage { 10 | CGFloat scale = [[UIScreen mainScreen] scale]; 11 | CGFloat scaledWidth = srcImage.size.width * (44.0f/srcImage.size.height); 12 | CGRect rect = CGRectMake(0, 0, scaledWidth, 44.0f); 13 | 14 | // Create the rounded-rect mask 15 | UIGraphicsBeginImageContextWithOptions(rect.size, NO, scale); 16 | CGContextRef ctx = UIGraphicsGetCurrentContext(); 17 | CGFloat radius = 10.0f; 18 | CGContextBeginPath(ctx); 19 | CGContextMoveToPoint(ctx, rect.origin.x, rect.origin.y + radius); 20 | CGContextAddLineToPoint(ctx, rect.origin.x, rect.origin.y + rect.size.height - radius); 21 | CGContextAddArc(ctx, rect.origin.x + radius, rect.origin.y + rect.size.height - radius, radius, M_PI, M_PI / 2, 1); 22 | CGContextAddLineToPoint(ctx, rect.origin.x + rect.size.width, rect.origin.y + rect.size.height); 23 | CGContextAddLineToPoint(ctx, rect.origin.x + rect.size.width, rect.origin.y); 24 | CGContextAddLineToPoint(ctx, rect.origin.x + radius, rect.origin.y); 25 | CGContextAddArc(ctx, rect.origin.x + radius, rect.origin.y + radius, radius, -M_PI / 2, M_PI, 1); 26 | CGContextClosePath(ctx); 27 | [[UIColor blackColor] set]; 28 | CGContextFillPath(ctx); 29 | UIImage *alphaMask = UIGraphicsGetImageFromCurrentImageContext(); 30 | UIGraphicsEndImageContext(); 31 | 32 | // Draw the image 33 | UIGraphicsBeginImageContextWithOptions(rect.size, NO, scale); 34 | ctx = UIGraphicsGetCurrentContext(); 35 | CGContextClipToMask(ctx, rect, alphaMask.CGImage); 36 | [srcImage drawInRect:rect]; 37 | UIImage *scaledImage = UIGraphicsGetImageFromCurrentImageContext(); 38 | UIGraphicsEndImageContext(); 39 | 40 | return scaledImage; 41 | } 42 | 43 | + (UIImage *) imageNamed:(NSString *)imageName { 44 | CGFloat scale = [UIScreen mainScreen].scale; 45 | CGFloat height = [UIScreen mainScreen].bounds.size.height; 46 | // For now, we require all -568h images to also be @2x. 47 | if (height == 568 && scale == 2) { 48 | NSString *expectedFn = [NSString stringWithFormat:@"%@-568h", imageName]; 49 | UIImage *attemptedImage = [UIImage imageNamed:expectedFn]; 50 | if (attemptedImage != nil) { 51 | return attemptedImage; 52 | } 53 | // fallthrough 54 | } 55 | return [UIImage imageNamed:imageName]; 56 | } 57 | 58 | // clearColorImage returns a 1x1 clearColor image 59 | // that can be used as a transparent background image 60 | // for UIKit APIs that force you to provide UIImages. 61 | + (UIImage *) clearColorImage { 62 | CGRect fillRect = CGRectMake(0.0, 0.0, 1.0, 1.0); 63 | UIGraphicsBeginImageContext(fillRect.size); 64 | CGContextRef ctx = UIGraphicsGetCurrentContext(); 65 | CGContextSetFillColorWithColor(ctx, [UIColor clearColor].CGColor); 66 | CGContextFillRect(ctx, fillRect); 67 | UIImage *img = UIGraphicsGetImageFromCurrentImageContext(); 68 | UIGraphicsEndImageContext(); 69 | return img; 70 | } 71 | 72 | @end 73 | -------------------------------------------------------------------------------- /Source/Classes/MURemoteControlPreferencesViewController.m: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | #import "MURemoteControlPreferencesViewController.h" 6 | #import "MURemoteControlServer.h" 7 | #import "MUImage.h" 8 | #import "MUBackgroundView.h" 9 | 10 | @interface MURemoteControlPreferencesViewController () { 11 | } 12 | @end 13 | 14 | @implementation MURemoteControlPreferencesViewController 15 | 16 | - (id) init { 17 | if ((self = [super initWithStyle:UITableViewStyleGrouped])) { 18 | } 19 | return self; 20 | } 21 | 22 | #pragma mark - View controller life cycle 23 | 24 | - (void) viewWillAppear:(BOOL)animated { 25 | self.navigationItem.title = NSLocalizedString(@"Remote Control", nil); 26 | 27 | self.tableView.backgroundView = [MUBackgroundView backgroundView]; 28 | 29 | if (@available(iOS 7, *)) { 30 | self.tableView.separatorStyle = UITableViewCellSeparatorStyleSingleLine; 31 | self.tableView.separatorInset = UIEdgeInsetsZero; 32 | } else { 33 | self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone; 34 | } 35 | 36 | self.tableView.scrollEnabled = NO; 37 | } 38 | 39 | #pragma mark - Table view data source 40 | 41 | - (NSInteger) numberOfSectionsInTableView:(UITableView *)tableView { 42 | return 2; 43 | } 44 | 45 | - (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 46 | if (section == 0) { 47 | return 1; 48 | } 49 | return 0; 50 | } 51 | 52 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 53 | static NSString *CellIdentifier = @"RemoteControlPrefsCell"; 54 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 55 | if (cell == nil) { 56 | cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier]; 57 | } 58 | 59 | if (indexPath.section == 0) { 60 | if (indexPath.row == 0) { 61 | cell.textLabel.text = @"Enable"; 62 | UISwitch *enableSwitch = [[UISwitch alloc] initWithFrame:CGRectZero]; 63 | [enableSwitch addTarget:self action:@selector(enableSwitchChanged:) forControlEvents:UIControlEventValueChanged]; 64 | enableSwitch.on = [[MURemoteControlServer sharedRemoteControlServer] isRunning]; 65 | enableSwitch.onTintColor = [UIColor blackColor]; 66 | cell.accessoryView = enableSwitch; 67 | cell.selectionStyle = UITableViewCellSelectionStyleNone; 68 | } 69 | } 70 | 71 | return cell; 72 | } 73 | 74 | 75 | 76 | #pragma mark - Table view delegate 77 | 78 | - (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 79 | } 80 | 81 | #pragma mark - Action 82 | 83 | - (void) enableSwitchChanged:(id)sender { 84 | UISwitch *enableSwitch = sender; 85 | MURemoteControlServer *server = [MURemoteControlServer sharedRemoteControlServer]; 86 | [[NSUserDefaults standardUserDefaults] setBool:enableSwitch.isOn forKey:@"RemoteControlServerEnabled"]; 87 | if (enableSwitch.isOn) { 88 | BOOL on = [server start]; 89 | if (!on) { 90 | enableSwitch.on = NO; 91 | } 92 | } else { 93 | [server stop]; 94 | } 95 | } 96 | 97 | @end 98 | -------------------------------------------------------------------------------- /Mumble.xcodeproj/xcshareddata/xcschemes/Mumble.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 37 | 38 | 39 | 40 | 41 | 42 | 52 | 54 | 60 | 61 | 62 | 63 | 69 | 71 | 77 | 78 | 79 | 80 | 82 | 83 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /Dependencies/MKNumberBadgeView/MKNumberBadgeView.h: -------------------------------------------------------------------------------- 1 | // 2 | // MKNumberBadgeView.h 3 | // 4 | // Copyright 2009 Michael F. Kamprath 5 | // michael@claireware.com 6 | // 7 | // Licensed under the Apache License, Version 2.0 (the "License"); 8 | // you may not use this file except in compliance with the License. 9 | // You may obtain a copy of the License at 10 | // 11 | // http://www.apache.org/licenses/LICENSE-2.0 12 | // 13 | // Unless required by applicable law or agreed to in writing, software 14 | // distributed under the License is distributed on an "AS IS" BASIS, 15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | // See the License for the specific language governing permissions and 17 | // limitations under the License. 18 | // 19 | // 20 | // MKNumberBadgeView 21 | // ----------------- 22 | // 23 | // Use this class to display a badge containing an integer value.Similar to the app icon badges that the iPhone OS permits. 24 | // 25 | // Notes: 26 | // * When creating the view, the frame used should be larger than the expected visual size of the badge view. Use the alignment 27 | // property to control the horizontal placement of the badge within the view's bounds. The badge will always be vertically 28 | // centered for the badge itself ignoring the size fo the shadow if it is enabled. 29 | // * The view's background color is automatically set to clear. If you change the background color, you may get curious results. 30 | // 31 | 32 | #import 33 | 34 | 35 | @interface MKNumberBadgeView : UIView 36 | { 37 | NSUInteger _value; 38 | 39 | UIFont* _font; 40 | UIColor* _fillColor; 41 | UIColor* _strokeColor; 42 | UIColor* _textColor; 43 | NSUInteger _pad; 44 | 45 | BOOL _shadow; 46 | BOOL _shine; 47 | 48 | CGSize _shadowOffset; 49 | 50 | NSTextAlignment _alignment; 51 | } 52 | 53 | // The current value displayed in the badge. Updating the value will update the view's display 54 | @property (assign,nonatomic) NSUInteger value; 55 | 56 | // Indicates whether the badge view draws a dhadow or not. 57 | @property (assign,nonatomic) BOOL shadow; 58 | 59 | // The offset for the shadow, if there is one. 60 | @property (assign,nonatomic) CGSize shadowOffset; 61 | 62 | // Indicates whether the badge view should be drawn with a shine 63 | @property (assign,nonatomic) BOOL shine; 64 | 65 | // The font to be used for drawing the numbers. NOTE: not all fonts are created equal for this purpose. 66 | // Only "system fonts" should be used. 67 | @property (retain,nonatomic) UIFont* font; 68 | 69 | // The color used for the background of the badge. 70 | @property (retain,nonatomic) UIColor* fillColor; 71 | 72 | // The color to be used for drawing the stroke around the badge. 73 | @property (retain,nonatomic) UIColor* strokeColor; 74 | 75 | // The color to be used for drawing the badge's numbers. 76 | @property (retain,nonatomic) UIColor* textColor; 77 | 78 | // How the badge image hould be aligned horizontally in the view. 79 | @property (assign,nonatomic) NSTextAlignment alignment; 80 | 81 | // Returns the visual size of the badge for the current value. Not the same hing as the size of the view's bounds. 82 | // The badge view bounds should be wider than space needed to draw the badge. 83 | @property (readonly,nonatomic) CGSize badgeSize; 84 | 85 | // The number of pixels between the number inside the badge and the stroke around the badge. This value 86 | // is approximate, as the font geometry might effectively slightly increase or decrease the apparent pad. 87 | @property (nonatomic) NSUInteger pad; 88 | 89 | @end 90 | -------------------------------------------------------------------------------- /Source/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | UIUserInterfaceStyle 6 | Light 7 | CFBundleDevelopmentRegion 8 | English 9 | CFBundleDisplayName 10 | ${PRODUCT_NAME} 11 | CFBundleExecutable 12 | ${EXECUTABLE_NAME} 13 | CFBundleIconFile 14 | icon.png 15 | CFBundleIconFiles 16 | 17 | icon.png 18 | icon@2x.png 19 | iconpad.png 20 | iconpad@2x.png 21 | 22 | CFBundleIcons 23 | 24 | CFBundlePrimaryIcon 25 | 26 | CFBundleIconFiles 27 | 28 | icon 29 | icon7 30 | icon.png 31 | icon@2x.png 32 | iconpad.png 33 | iconpad@2x.png 34 | 35 | UIPrerenderedIcon 36 | 37 | 38 | 39 | CFBundleIdentifier 40 | $(PRODUCT_BUNDLE_IDENTIFIER) 41 | CFBundleInfoDictionaryVersion 42 | 6.0 43 | CFBundleName 44 | ${PRODUCT_NAME} 45 | CFBundlePackageType 46 | APPL 47 | CFBundleShortVersionString 48 | 1.3.1 49 | CFBundleSignature 50 | ???? 51 | CFBundleURLTypes 52 | 53 | 54 | CFBundleTypeRole 55 | Editor 56 | CFBundleURLIconFile 57 | Icon 58 | CFBundleURLName 59 | info.mumble.Mumble 60 | CFBundleURLSchemes 61 | 62 | mumble 63 | 64 | 65 | 66 | CFBundleVersion 67 | 1003001001 68 | NSMainNibFile 69 | MainWindow 70 | NSMicrophoneUsageDescription 71 | Mumble uses your microphone for voice chats 72 | UIBackgroundModes 73 | 74 | audio 75 | voip 76 | 77 | UIFileSharingEnabled 78 | 79 | UILaunchImages 80 | 81 | 82 | UILaunchImageMinimumOSVersion 83 | 7.0 84 | UILaunchImageName 85 | Default-iOS7 86 | UILaunchImageOrientation 87 | Portrait 88 | UILaunchImageSize 89 | {320, 480} 90 | 91 | 92 | UILaunchImageMinimumOSVersion 93 | 7.0 94 | UILaunchImageName 95 | Default-iOS7 96 | UILaunchImageOrientation 97 | Portrait 98 | UILaunchImageSize 99 | {320, 568} 100 | 101 | 102 | UILaunchStoryboardName 103 | LaunchScreen 104 | UIPrerenderedIcon 105 | 106 | UIStatusBarStyle 107 | UIStatusBarStyleDefault 108 | UISupportedInterfaceOrientations 109 | 110 | UIInterfaceOrientationPortrait 111 | 112 | 113 | 114 | -------------------------------------------------------------------------------- /Source/Classes/MUAudioMixerDebugViewController.m: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | #import "MUAudioMixerDebugViewController.h" 6 | #import 7 | 8 | @interface MUAudioMixerDebugViewController () { 9 | NSDictionary *_mixerInfo; 10 | NSTimer *_timer; 11 | } 12 | @end 13 | 14 | @implementation MUAudioMixerDebugViewController 15 | 16 | - (id) init { 17 | if ((self = [super initWithStyle:UITableViewStylePlain])) { 18 | // ... 19 | } 20 | return self; 21 | } 22 | 23 | - (void) viewWillAppear:(BOOL)animated { 24 | [[self navigationItem] setTitle:@"Mixer Debug"]; 25 | 26 | UIBarButtonItem *doneButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(doneDebugging:)]; 27 | [[self navigationItem] setRightBarButtonItem:doneButton]; 28 | 29 | _timer = [NSTimer scheduledTimerWithTimeInterval:0.001 target:self selector:@selector(updateMixerInfo:) userInfo:nil repeats:YES]; 30 | [self updateMixerInfo:self]; 31 | } 32 | 33 | - (void) viewWillDisappear:(BOOL)animated { 34 | [_timer invalidate]; 35 | } 36 | 37 | - (void) updateMixerInfo:(id)sender { 38 | _mixerInfo = [[MKAudio sharedAudio] copyAudioOutputMixerDebugInfo]; 39 | [[self tableView] reloadData]; 40 | } 41 | 42 | #pragma mark - Table view data source 43 | 44 | - (NSInteger) numberOfSectionsInTableView:(UITableView *)tableView { 45 | return 3; 46 | } 47 | 48 | - (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 49 | if (section == 0) { // Metadata 50 | return 1; 51 | } else if (section == 1) { // Sources 52 | return [[_mixerInfo objectForKey:@"sources"] count]; 53 | } else if (section == 1) { // Removed 54 | return [[_mixerInfo objectForKey:@"removed"] count]; 55 | } 56 | 57 | return 0; 58 | } 59 | 60 | - (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 61 | static NSString *CellIdentifier = @"AudioMixerDebugCell"; 62 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 63 | if (cell == nil) { 64 | cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier]; 65 | } 66 | 67 | if (indexPath.section == 0) { // Meta 68 | if (indexPath.row == 0) { // Last Update 69 | NSDateFormatter *fmt = [[NSDateFormatter alloc] init]; 70 | [fmt setDateFormat:@"HH:mm:ss:SSS"]; 71 | NSDate *date = [_mixerInfo objectForKey:@"last-update"]; 72 | cell.textLabel.text = @"Last Updated"; 73 | cell.detailTextLabel.text = [fmt stringFromDate:date]; 74 | } 75 | } 76 | 77 | if (indexPath.section == 1) { 78 | NSDictionary *info = [[_mixerInfo objectForKey:@"sources"] objectAtIndex:indexPath.row]; 79 | cell.textLabel.text = [info objectForKey:@"kind"]; 80 | cell.detailTextLabel.text = [info objectForKey:@"identifier"]; 81 | } else if (indexPath.section == 2) { 82 | NSDictionary *info = [[_mixerInfo objectForKey:@"removed"] objectAtIndex:indexPath.row]; 83 | cell.textLabel.text = [info objectForKey:@"kind"]; 84 | cell.detailTextLabel.text = [info objectForKey:@"identifier"]; } 85 | 86 | cell.selectionStyle = UITableViewCellSelectionStyleNone; 87 | 88 | return cell; 89 | } 90 | - (NSString *) tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { 91 | if (section == 0) { 92 | return @"Metadata"; 93 | } else if (section == 1) { 94 | return @"Sources"; 95 | } else if (section == 2) { 96 | return @"Removed"; 97 | } 98 | 99 | return @"Unknown"; 100 | } 101 | 102 | - (void) doneDebugging:(id)sender { 103 | [self dismissViewControllerAnimated:YES completion:nil]; 104 | } 105 | 106 | @end 107 | -------------------------------------------------------------------------------- /Source/Classes/MUNotificationController.m: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2011 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | #import "MUNotificationController.h" 6 | 7 | @interface MUNotificationController () { 8 | UIView *_notificationView; 9 | NSMutableArray *_notificationQueue; 10 | BOOL _running; 11 | CGRect _keyboardFrame; 12 | } 13 | - (void) showNext; 14 | - (void) hideCurrent; 15 | @end 16 | 17 | @implementation MUNotificationController 18 | 19 | + (MUNotificationController *) sharedController { 20 | static MUNotificationController *nc; 21 | static dispatch_once_t token; 22 | dispatch_once(&token, ^{ 23 | nc = [[MUNotificationController alloc] init]; 24 | }); 25 | return nc; 26 | } 27 | 28 | - (id) init { 29 | if ((self = [super init])) { 30 | _notificationQueue = [[NSMutableArray alloc] init]; 31 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardDidShow:) name:UIKeyboardDidShowNotification object:nil]; 32 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardDidHide:) name:UIKeyboardDidHideNotification object:nil]; 33 | } 34 | return self; 35 | } 36 | 37 | - (void) dealloc { 38 | [[NSNotificationCenter defaultCenter] removeObserver:self]; 39 | } 40 | 41 | - (void) keyboardDidShow:(NSNotification *)notification { 42 | NSDictionary *userInfo = [notification userInfo]; 43 | NSValue *val = [userInfo valueForKey:UIKeyboardFrameEndUserInfoKey]; 44 | [val getValue:&_keyboardFrame]; 45 | } 46 | 47 | - (void) keyboardDidHide:(NSNotification *)notification { 48 | _keyboardFrame = CGRectZero; 49 | } 50 | 51 | - (void) addNotification:(NSString *)text { 52 | if ([_notificationQueue count] < 10) 53 | [_notificationQueue addObject:[text copy]]; 54 | if (!_running) { 55 | [self showNext]; 56 | } 57 | } 58 | 59 | - (void) showNext { 60 | _running = YES; 61 | 62 | UIScreen *screen = [UIScreen mainScreen]; 63 | CGRect bounds = screen.bounds; 64 | 65 | CGFloat width = ceilf(bounds.size.width - 50.0f); 66 | CGFloat height = 50.0f; 67 | 68 | CGRect frame = CGRectMake(25.0f, ceilf((bounds.size.height - _keyboardFrame.size.height)/2) - 25.0f, width, height); 69 | UIView *container = [[UIView alloc] initWithFrame:frame]; 70 | container.alpha = 0.0f; 71 | container.userInteractionEnabled = NO; 72 | 73 | UIView *bg = [[UIView alloc] initWithFrame:CGRectMake(0, 0, width, height)]; 74 | bg.layer.cornerRadius = 8.0f; 75 | bg.backgroundColor = [UIColor blackColor]; 76 | bg.alpha = 0.8f; 77 | [container addSubview:bg]; 78 | 79 | UILabel *lbl = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, width, height)]; 80 | lbl.font = [UIFont systemFontOfSize:16.0f]; 81 | NSString *notificationText = [_notificationQueue objectAtIndex:0]; 82 | lbl.text = notificationText; 83 | [_notificationQueue removeObjectAtIndex:0]; 84 | lbl.textColor = [UIColor whiteColor]; 85 | lbl.backgroundColor = [UIColor clearColor]; 86 | lbl.textAlignment = NSTextAlignmentCenter; 87 | [container addSubview:lbl]; 88 | 89 | [[[UIApplication sharedApplication] keyWindow] addSubview:container]; 90 | 91 | self->_notificationView = container; 92 | [UIView animateWithDuration:0.1f animations:^{ 93 | self->_notificationView.alpha = 1.0f; 94 | } completion:^(BOOL completed) { 95 | NSTimer *timer = [NSTimer timerWithTimeInterval:0.3f target:self selector:@selector(hideCurrent) userInfo:nil repeats:NO]; 96 | [[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes]; 97 | }]; 98 | } 99 | 100 | - (void) hideCurrent { 101 | [UIView animateWithDuration:0.1f animations:^{ 102 | self->_notificationView.alpha = 0.0f; 103 | } completion:^(BOOL completed) { 104 | [self->_notificationView removeFromSuperview]; 105 | self->_notificationView = nil; 106 | if ([self->_notificationQueue count] > 0) { 107 | [self performSelectorOnMainThread:@selector(showNext) withObject:nil waitUntilDone:NO]; 108 | } else { 109 | self->_running = NO; 110 | } 111 | }]; 112 | } 113 | 114 | @end 115 | -------------------------------------------------------------------------------- /Source/Classes/MUAudioBarView.m: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2011 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | #import "MUAudioBarView.h" 6 | #import "MUColor.h" 7 | 8 | #import 9 | 10 | @interface MUAudioBarView () { 11 | CGFloat _below; 12 | CGFloat _above; 13 | CGFloat _min; 14 | CGFloat _max; 15 | CGFloat _value; 16 | NSTimer *_timer; 17 | } 18 | @end 19 | 20 | @implementation MUAudioBarView 21 | 22 | - (id) initWithFrame:(CGRect)frame { 23 | if ((self = [super initWithFrame:frame])) { 24 | _value = 0.5f; 25 | _min = 0.0f; 26 | _max = 1.0f; 27 | _timer = [NSTimer timerWithTimeInterval:1/60.0f target:self selector:@selector(tickTock) userInfo:nil repeats:YES]; 28 | [[NSRunLoop mainRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes]; 29 | } 30 | return self; 31 | } 32 | 33 | - (void) dealloc { 34 | [_timer invalidate]; 35 | } 36 | 37 | - (void) setBelow:(CGFloat)below { 38 | _below = below; 39 | } 40 | 41 | - (void) setAbove:(CGFloat)above { 42 | _above = above; 43 | } 44 | 45 | - (void) drawRect:(CGRect)rect { 46 | CGRect bounds = self.bounds; 47 | CGContextRef ctx = UIGraphicsGetCurrentContext(); 48 | CGContextClearRect(ctx, bounds); 49 | 50 | _below = [[NSUserDefaults standardUserDefaults] floatForKey:@"AudioVADBelow"]; 51 | _above = [[NSUserDefaults standardUserDefaults] floatForKey:@"AudioVADAbove"]; 52 | 53 | CGFloat scale = bounds.size.width / (_max - _min); 54 | int below = (int)((_below-_min)*scale); 55 | int above = (int)((_above-_min)*scale); 56 | int value = (int)((_value-_min)*scale); 57 | 58 | CGColorRef redA = [[MUColor badPingColor] colorWithAlphaComponent:0.6f].CGColor; 59 | CGColorRef redO = [MUColor badPingColor].CGColor; 60 | CGColorRef yellowA = [[MUColor mediumPingColor] colorWithAlphaComponent:0.6f].CGColor; 61 | CGColorRef yellowO = [MUColor mediumPingColor].CGColor; 62 | CGColorRef greenA = [[MUColor goodPingColor] colorWithAlphaComponent:0.6f].CGColor; 63 | CGColorRef greenO = [MUColor goodPingColor].CGColor; 64 | 65 | if (_above < _below) { 66 | CGContextSetFillColorWithColor(ctx, redA); 67 | CGContextFillRect(ctx, bounds); 68 | return; 69 | } 70 | 71 | CGRect redBounds = CGRectMake(bounds.origin.x, 0, below, bounds.size.height); 72 | CGContextSetFillColorWithColor(ctx, redA); 73 | CGContextFillRect(ctx, redBounds); 74 | 75 | int x = redBounds.size.width; 76 | CGRect yellowBounds = CGRectMake(x, 0, above-x, bounds.size.height); 77 | CGContextSetFillColorWithColor(ctx, yellowA); 78 | CGContextFillRect(ctx, yellowBounds); 79 | 80 | x = yellowBounds.origin.x+yellowBounds.size.width; 81 | CGRect greenBounds = CGRectMake(x, 0, bounds.size.width-x, bounds.size.height); 82 | CGContextSetFillColorWithColor(ctx, greenA); 83 | CGContextFillRect(ctx, greenBounds); 84 | 85 | if (value > below) { 86 | CGContextSetFillColorWithColor(ctx, redO); 87 | CGContextFillRect(ctx, redBounds); 88 | } else { 89 | redBounds = CGRectMake(bounds.origin.x, 0, value, bounds.size.height); 90 | CGContextSetFillColorWithColor(ctx, redO); 91 | CGContextFillRect(ctx, redBounds); 92 | } 93 | if (value > above) { 94 | CGContextSetFillColorWithColor(ctx, yellowO); 95 | CGContextFillRect(ctx, yellowBounds); 96 | 97 | greenBounds = CGRectMake(x, 0, value-x, bounds.size.height); 98 | CGContextSetFillColorWithColor(ctx, greenO); 99 | CGContextFillRect(ctx, greenBounds); 100 | } else if (value > below && value <= above) { 101 | x = redBounds.size.width; 102 | CGRect yellowBounds = CGRectMake(x, 0, value-x, bounds.size.height); 103 | CGContextSetFillColorWithColor(ctx, yellowO); 104 | CGContextFillRect(ctx, yellowBounds); 105 | } 106 | } 107 | 108 | - (void) tickTock { 109 | MKAudio *audio = [MKAudio sharedAudio]; 110 | NSString *kind = [[NSUserDefaults standardUserDefaults] objectForKey:@"AudioVADKind"]; 111 | if (![[NSUserDefaults standardUserDefaults] boolForKey:@"AudioPreprocessor"]) 112 | kind = @"amplitude"; 113 | if ([kind isEqualToString:@"snr"]) { 114 | _value = [audio speechProbablity]; 115 | } else { 116 | _value = ([audio peakCleanMic] + 96.0)/96.0; 117 | } 118 | [self setNeedsDisplay]; 119 | } 120 | 121 | @end 122 | -------------------------------------------------------------------------------- /Tests/MUTextMessageProcessorTest.m: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | #import "MUTextMessageProcessorTest.h" 6 | #import "MUTextMessageProcessor.h" 7 | 8 | @interface MUTextMessageProcessorTest () 9 | + (NSString *) plainStringFromLinks:(NSArray *)links; 10 | + (NSString *) htmlStringFromLinks:(NSArray *)links; 11 | @end 12 | 13 | @implementation MUTextMessageProcessorTest 14 | 15 | - (void)setUp { 16 | [super setUp]; 17 | } 18 | 19 | - (void)tearDown { 20 | [super tearDown]; 21 | } 22 | 23 | - (void) testSingleLink { 24 | NSString *plain = @"Hello there. Here's a link: http://www.google.com"; 25 | NSString *expected = @"

Hello there. Here's a link: http://www.google.com

"; 26 | NSString *html = [MUTextMessageProcessor processedHTMLFromPlainTextMessage:plain]; 27 | STAssertEqualObjects(html, expected, nil); 28 | } 29 | 30 | - (void) testSingleLinkWithTrailer { 31 | NSString *plain = @"Hello there. Here's a link: http://www.google.com, and a trailer!"; 32 | NSString *expected = @"

Hello there. Here's a link: http://www.google.com, and a trailer!

"; 33 | NSString *html = [MUTextMessageProcessor processedHTMLFromPlainTextMessage:plain]; 34 | STAssertEqualObjects(html, expected, nil); 35 | } 36 | 37 | - (void) testMultiLink { 38 | NSString *plain = @"1st: http://www.a.com, 2nd: http://www.b.com"; 39 | NSString *expected = @"

1st: http://www.a.com, 2nd: http://www.b.com

"; 40 | NSString *html = [MUTextMessageProcessor processedHTMLFromPlainTextMessage:plain]; 41 | STAssertEqualObjects(html, expected, nil); 42 | } 43 | 44 | - (void) testPercentEncoding { 45 | NSString *plain = @"Hello there. Here's a link: http://www.example.com/%20a%20lot%20of%20spaces"; 46 | NSString *expected = @"

Hello there. Here's a link: http://www.example.com/%20a%20lot%20of%20spaces

"; 47 | NSString *html = [MUTextMessageProcessor processedHTMLFromPlainTextMessage:plain]; 48 | STAssertEqualObjects(html, expected, nil); 49 | } 50 | 51 | + (NSString *) plainStringFromLinks:(NSArray *)links { 52 | NSMutableString *str = [NSMutableString string]; 53 | for (NSString *url in links) { 54 | [str appendString:url]; 55 | [str appendString:@" "]; 56 | } 57 | return str; 58 | } 59 | 60 | + (NSString *) htmlStringFromLinks:(NSArray *)links { 61 | NSMutableString *str = [NSMutableString string]; 62 | [str appendString:@"

"]; 63 | for (NSString *url in links) { 64 | [str appendString:@""]; 67 | [str appendString:url]; 68 | [str appendString:@" "]; 69 | } 70 | [str appendString:@"

"]; 71 | return str; 72 | } 73 | 74 | - (void) testManyLinks { 75 | NSArray *links = @[ 76 | @"http://www.google.com", 77 | @"http://www.facebook.com", 78 | @"https://www.yahoo.com", 79 | @"mumble://test.mumble.info:64738", 80 | @"mumble://test.mumble.info:64738/Test/Some/Channel?version=1.2.0" 81 | @"steam://43145", 82 | @"mailto:test@example.com", 83 | @"file:///Users/luser/Documents/test.html", 84 | @"http://www.google.dk/#hl=en&safe=off&tbo=d&output=search&sclient=psy-ab&q=hello+world&oq=hello+world", 85 | @"http://www.bing.com/%20%20already%20%20percent%20%20encoded", 86 | @"http://www.nonascii.com/æøæåæøæåææøæåæø", 87 | @"http://pctenc.info/%26%25%26%25", 88 | ]; 89 | NSString *plain = [MUTextMessageProcessorTest plainStringFromLinks:links]; 90 | NSString *expected = [MUTextMessageProcessorTest htmlStringFromLinks:links]; 91 | NSString *html = [MUTextMessageProcessor processedHTMLFromPlainTextMessage:plain]; 92 | STAssertEqualObjects(html, expected, nil); 93 | } 94 | 95 | - (void) testInvalidURLs { 96 | NSArray *links = @[ 97 | @"http://currency.eu/€€€", 98 | @"http://bah/?hello#hey#ho", 99 | ]; 100 | for (NSString *url in links) { 101 | NSString *plain = [MUTextMessageProcessorTest plainStringFromLinks:links]; 102 | NSString *expected = [MUTextMessageProcessorTest htmlStringFromLinks:links]; 103 | NSString *html = [MUTextMessageProcessor processedHTMLFromPlainTextMessage:plain]; 104 | STAssertFalse([html isEqualToString:expected], @"got '%@', did not expect '%@'", html, expected); 105 | } 106 | } 107 | 108 | @end 109 | -------------------------------------------------------------------------------- /Source/Classes/MUPublicServerListController.m: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2010 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | #import "MUPublicServerList.h" 6 | #import "MUPublicServerListController.h" 7 | #import "MUCountryServerListController.h" 8 | #import "MUTableViewHeaderLabel.h" 9 | #import "MUImage.h" 10 | #import "MUBackgroundView.h" 11 | 12 | @interface MUPublicServerListController () { 13 | MUPublicServerList *_serverList; 14 | } 15 | @end 16 | 17 | @implementation MUPublicServerListController 18 | 19 | - (id) init { 20 | if ((self = [super initWithStyle:UITableViewStyleGrouped])) { 21 | _serverList = [[MUPublicServerList alloc] init]; 22 | } 23 | return self; 24 | } 25 | 26 | - (void) viewWillAppear:(BOOL)animated { 27 | [super viewWillAppear:YES]; 28 | 29 | self.navigationItem.title = NSLocalizedString(@"Public Servers", nil); 30 | 31 | self.tableView.backgroundView = [MUBackgroundView backgroundView]; 32 | 33 | if (@available(iOS 7, *)) { 34 | self.tableView.separatorStyle = UITableViewCellSeparatorStyleSingleLine; 35 | self.tableView.separatorInset = UIEdgeInsetsZero; 36 | } else { 37 | self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone; 38 | } 39 | 40 | if (![_serverList isParsed]) { 41 | UIActivityIndicatorView *activityIndicatorView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite]; 42 | UIBarButtonItem *barActivityIndicator = [[UIBarButtonItem alloc] initWithCustomView:activityIndicatorView]; 43 | self.navigationItem.rightBarButtonItem = barActivityIndicator; 44 | [activityIndicatorView startAnimating]; 45 | } 46 | } 47 | 48 | - (void) viewDidAppear:(BOOL)animated { 49 | [super viewDidAppear:YES]; 50 | 51 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 52 | if ([self->_serverList isParsed]) { 53 | self.navigationItem.rightBarButtonItem = nil; 54 | return; 55 | } 56 | [self->_serverList parse]; 57 | dispatch_async(dispatch_get_main_queue(), ^{ 58 | self.navigationItem.rightBarButtonItem = nil; 59 | [self.tableView reloadData]; 60 | }); 61 | }); 62 | } 63 | 64 | #pragma mark - 65 | #pragma mark UITableView data source 66 | 67 | - (NSInteger) numberOfSectionsInTableView:(UITableView *)tableView { 68 | return [_serverList numberOfContinents]; 69 | } 70 | 71 | - (UIView *) tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { 72 | return [MUTableViewHeaderLabel labelWithText:[_serverList continentNameAtIndex:section]]; 73 | } 74 | 75 | - (CGFloat) tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section { 76 | return [MUTableViewHeaderLabel defaultHeaderHeight]; 77 | } 78 | 79 | 80 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 81 | return [_serverList numberOfCountriesAtContinentIndex:section]; 82 | } 83 | 84 | - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { 85 | return 50.0; 86 | } 87 | 88 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 89 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"countryItem"]; 90 | if (!cell) { 91 | cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"countryItem"]; 92 | } 93 | 94 | [cell setAccessoryType:UITableViewCellAccessoryDisclosureIndicator]; 95 | NSDictionary *countryInfo = [_serverList countryAtIndexPath:indexPath]; 96 | cell.textLabel.text = [countryInfo objectForKey:@"name"]; 97 | NSInteger numServers = [[countryInfo objectForKey:@"servers"] count]; 98 | cell.detailTextLabel.text = [NSString stringWithFormat:@"%li %@", (long int)numServers, numServers > 1 ? @"servers" : @"server"]; 99 | cell.selectionStyle = UITableViewCellSelectionStyleGray; 100 | 101 | return cell; 102 | } 103 | 104 | #pragma mark - 105 | #pragma mark UITableView delegate 106 | 107 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 108 | NSDictionary *countryInfo = [_serverList countryAtIndexPath:indexPath]; 109 | NSString *countryName = [countryInfo objectForKey:@"name"]; 110 | NSArray *countryServers = [countryInfo objectForKey:@"servers"]; 111 | 112 | MUCountryServerListController *countryController = [[MUCountryServerListController alloc] initWithName:countryName serverList:countryServers]; 113 | [[self navigationController] pushViewController:countryController animated:YES]; 114 | } 115 | 116 | @end 117 | -------------------------------------------------------------------------------- /Source/Classes/MUAudioSidetonePreferencesViewController.m: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2011 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | #import "MUAudioSidetonePreferencesViewController.h" 6 | #import "MUTableViewHeaderLabel.h" 7 | #import "MUColor.h" 8 | #import "MUImage.h" 9 | #import "MUBackgroundView.h" 10 | 11 | @implementation MUAudioSidetonePreferencesViewController 12 | 13 | - (id) init { 14 | if ((self = [super initWithStyle:UITableViewStyleGrouped])) { 15 | self.preferredContentSize = CGSizeMake(320, 480); 16 | } 17 | return self; 18 | } 19 | 20 | - (void) viewWillAppear:(BOOL)animated { 21 | [super viewWillAppear:animated]; 22 | 23 | self.title = NSLocalizedString(@"Sidetone", nil); 24 | 25 | self.tableView.backgroundView = [MUBackgroundView backgroundView]; 26 | 27 | if (@available(iOS 7, *)) { 28 | self.tableView.separatorStyle = UITableViewCellSeparatorStyleSingleLine; 29 | self.tableView.separatorInset = UIEdgeInsetsZero; 30 | } else { 31 | self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone; 32 | } 33 | 34 | self.tableView.scrollEnabled = NO; 35 | } 36 | 37 | #pragma mark - Table view data source 38 | 39 | - (NSInteger) numberOfSectionsInTableView:(UITableView *)tableView { 40 | return 1; 41 | } 42 | 43 | - (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 44 | return 2; 45 | } 46 | 47 | - (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 48 | static NSString *CellIdentifier = @"MUAudioSidetonePreferencesCell"; 49 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 50 | if (cell == nil) { 51 | cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier]; 52 | } 53 | 54 | NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; 55 | 56 | cell.selectionStyle = UITableViewCellSelectionStyleGray; 57 | cell.accessoryView = nil; 58 | cell.selectionStyle = UITableViewCellSelectionStyleNone; 59 | 60 | if ([indexPath section] == 0) { 61 | if ([indexPath row] == 0) { 62 | cell.textLabel.text = NSLocalizedString(@"Enable Sidetone", nil); 63 | UISwitch *sidetoneSwitch = [[UISwitch alloc] init]; 64 | [sidetoneSwitch setOnTintColor:[UIColor blackColor]]; 65 | [sidetoneSwitch addTarget:self action:@selector(sidetoneStatusChanged:) forControlEvents:UIControlEventValueChanged]; 66 | [sidetoneSwitch setOn:[defaults boolForKey:@"AudioSidetone"]]; 67 | cell.accessoryView = sidetoneSwitch; 68 | } else if ([indexPath row] == 1) { 69 | NSLog(@"reloadin' (enabled? %u)", [defaults boolForKey:@"AudioSidetone"]); 70 | cell.textLabel.text = NSLocalizedString(@"Playback Volume", nil); 71 | UISlider *sidetoneSlider = [[UISlider alloc] init]; 72 | [sidetoneSlider addTarget:self action:@selector(sidetoneVolumeChanged:) forControlEvents:UIControlEventValueChanged]; 73 | [sidetoneSlider setEnabled:[defaults boolForKey:@"AudioSidetone"]]; 74 | [sidetoneSlider setMinimumValue:0.0f]; 75 | [sidetoneSlider setMaximumValue:1.0f]; 76 | [sidetoneSlider setValue:[defaults floatForKey:@"AudioSidetoneVolume"]]; 77 | [sidetoneSlider setMinimumTrackTintColor:[UIColor blackColor]]; 78 | cell.accessoryView = sidetoneSlider; 79 | } 80 | } 81 | 82 | return cell; 83 | } 84 | 85 | - (UIView *) tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { 86 | if (section == 0) { 87 | return [MUTableViewHeaderLabel labelWithText:NSLocalizedString(@"Sidetone Feedback", nil)]; 88 | } 89 | return nil; 90 | } 91 | 92 | - (CGFloat) tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section { 93 | if (section == 0) { 94 | return [MUTableViewHeaderLabel defaultHeaderHeight]; 95 | } 96 | return 0.0f; 97 | } 98 | 99 | #pragma mark - Actions 100 | 101 | - (void) sidetoneStatusChanged:(UISwitch *)sidetoneSwitch { 102 | NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; 103 | [defaults setBool:[sidetoneSwitch isOn] forKey:@"AudioSidetone"]; 104 | [[self tableView] reloadRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:1 inSection:0]] withRowAnimation:UITableViewRowAnimationNone]; 105 | } 106 | 107 | - (void) sidetoneVolumeChanged:(UISlider *)sidetoneSlider { 108 | NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; 109 | [defaults setFloat:[sidetoneSlider value] forKey:@"AudioSidetoneVolume"]; 110 | } 111 | 112 | @end 113 | -------------------------------------------------------------------------------- /Source/Classes/MUMessageAttachmentViewController.m: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2012 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | #import "MUMessageAttachmentViewController.h" 6 | #import "MUTableViewHeaderLabel.h" 7 | #import "MUImageViewController.h" 8 | #import "MUImage.h" 9 | #import "MUBackgroundView.h" 10 | 11 | @interface MUMessageAttachmentViewController () { 12 | NSArray *_links; 13 | NSArray *_images; 14 | } 15 | @end 16 | 17 | @implementation MUMessageAttachmentViewController 18 | 19 | - (id) initWithImages:(NSArray *)images andLinks:(NSArray *)links { 20 | if ((self = [super initWithStyle:UITableViewStyleGrouped])) { 21 | _images = images; 22 | _links = links; 23 | } 24 | return self; 25 | } 26 | 27 | #pragma mark - View lifecycle 28 | 29 | - (void) viewWillAppear:(BOOL)animated { 30 | [super viewWillAppear:animated]; 31 | 32 | self.navigationItem.title = NSLocalizedString(@"Attachments", nil); 33 | 34 | self.tableView.backgroundView = [MUBackgroundView backgroundView]; 35 | 36 | if (@available(iOS 7, *)) { 37 | self.tableView.separatorStyle = UITableViewCellSeparatorStyleSingleLine; 38 | self.tableView.separatorInset = UIEdgeInsetsZero; 39 | } else { 40 | self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone; 41 | } 42 | } 43 | 44 | #pragma mark - Table view data source 45 | 46 | - (NSInteger) numberOfSectionsInTableView:(UITableView *)tableView { 47 | BOOL hasImages = [_images count] > 0; 48 | if (hasImages) { 49 | return 2; 50 | } else { 51 | return 1; 52 | } 53 | return 0; 54 | } 55 | 56 | - (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 57 | BOOL hasImages = [_images count] > 0; 58 | if (hasImages && section == 0) { 59 | return 1; 60 | } else { 61 | return [_links count]; 62 | } 63 | return 0; 64 | } 65 | 66 | - (UIView *) tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { 67 | BOOL hasImages = [_images count] > 0; 68 | if (hasImages && section == 0) { 69 | return [MUTableViewHeaderLabel labelWithText:NSLocalizedString(@"Images", nil)]; 70 | } else { 71 | return [MUTableViewHeaderLabel labelWithText:NSLocalizedString(@"Links", nil)]; 72 | } 73 | return nil; 74 | } 75 | 76 | - (CGFloat) tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section { 77 | return [MUTableViewHeaderLabel defaultHeaderHeight]; 78 | } 79 | 80 | - (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 81 | static NSString *CellIdentifier = @"Cell"; 82 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 83 | if (cell == nil) { 84 | cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier]; 85 | } 86 | 87 | cell.selectionStyle = UITableViewCellSelectionStyleGray; 88 | 89 | BOOL hasImages = [_images count] > 0; 90 | if (hasImages && [indexPath section] == 0) { 91 | UIImage *img = [_images objectAtIndex:0]; 92 | UIImage *round = [MUImage tableViewCellImageFromImage:img]; 93 | [cell.imageView setImage:round]; 94 | cell.textLabel.text = NSLocalizedString(@"Images", nil); 95 | NSString *detailText = NSLocalizedString(@"1 image", nil); 96 | if ([_images count] > 1) 97 | detailText = [NSString stringWithFormat:NSLocalizedString(@"%lu images", nil), (unsigned long)[_images count]]; 98 | cell.detailTextLabel.text = detailText; 99 | cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; 100 | } else { 101 | cell.imageView.image = nil; 102 | NSString *urlStr = [_links objectAtIndex:[indexPath row]]; 103 | NSURL *url = [NSURL URLWithString:urlStr]; 104 | cell.textLabel.text = [url host]; 105 | cell.detailTextLabel.text = urlStr; 106 | } 107 | 108 | return cell; 109 | } 110 | 111 | #pragma mark - Table view delegate 112 | 113 | - (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 114 | BOOL hasImages = [_images count] > 0; 115 | if (hasImages && [indexPath section] == 0) { 116 | MUImageViewController *imgViewController = [[MUImageViewController alloc] initWithImages:_images]; 117 | [self.navigationController pushViewController:imgViewController animated:YES]; 118 | } else { 119 | [[UIApplication sharedApplication] openURL:[NSURL URLWithString:[_links objectAtIndex:[indexPath row]]] options:@{} completionHandler:nil]; 120 | } 121 | 122 | [self.tableView deselectRowAtIndexPath:indexPath animated:YES]; 123 | } 124 | 125 | @end 126 | -------------------------------------------------------------------------------- /Source/Classes/MURemoteControlServer.m: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #import "MURemoteControlServer.h" 11 | 12 | #import 13 | 14 | @interface MURemoteControlServer () { 15 | NSMutableArray *_activeSocks; 16 | CFSocketRef _sock; 17 | } 18 | - (void) addSocket:(NSNumber *)socketNumber; 19 | - (void) removeSocket:(NSNumber *)socketNumber; 20 | @end 21 | 22 | static void *serverThread(void *udata) { 23 | int sock = (int) (long) udata; 24 | unsigned char action; 25 | 26 | int val = 1; 27 | if (setsockopt(sock, SOL_SOCKET, SO_NOSIGPIPE, &val, sizeof(val)) == -1) 28 | goto out; 29 | 30 | while (1) { 31 | ssize_t nread = read(sock, &action, 1); 32 | if (nread == 0) { 33 | goto out; 34 | } 35 | if (nread == -1) { 36 | NSLog(@"MURemoteControlServer: aborted server thread: %s", strerror(errno)); 37 | goto out; 38 | } 39 | 40 | unsigned char on = action & 0x1; 41 | unsigned char code = action & ~0x1; 42 | if (code == 0) { // PTT 43 | MKAudio *audio = [MKAudio sharedAudio]; 44 | [audio setForceTransmit:on > 0]; 45 | } 46 | } 47 | out: 48 | @autoreleasepool { 49 | MURemoteControlServer *remoteControlServer = [MURemoteControlServer sharedRemoteControlServer]; 50 | NSNumber *socketNumber = [NSNumber numberWithInt:sock]; 51 | [remoteControlServer performSelector:@selector(removeSocket:) onThread:[NSThread mainThread] withObject:socketNumber waitUntilDone:NO]; 52 | } 53 | return NULL; 54 | } 55 | 56 | static void acceptCallBack(CFSocketRef socket, CFSocketCallBackType type, CFDataRef address, const void *data, void *info) { 57 | MURemoteControlServer *remoteControl = (__bridge MURemoteControlServer *) info; 58 | int sock = *(int *)data; 59 | [remoteControl addSocket:[NSNumber numberWithInt:sock]]; 60 | if (type == kCFSocketAcceptCallBack) { 61 | pthread_t thr; 62 | pthread_create(&thr, NULL, serverThread, (void *)((uintptr_t)sock)); 63 | } 64 | } 65 | 66 | @implementation MURemoteControlServer 67 | 68 | + (MURemoteControlServer *) sharedRemoteControlServer { 69 | static dispatch_once_t token; 70 | static MURemoteControlServer *remoteControlServer; 71 | dispatch_once(&token, ^{ 72 | remoteControlServer = [[MURemoteControlServer alloc] init]; 73 | }); 74 | return remoteControlServer; 75 | } 76 | 77 | - (id) init { 78 | if ((self = [super init])) { 79 | } 80 | return self; 81 | } 82 | 83 | - (void) addSocket:(NSNumber *)socketNumber { 84 | [_activeSocks addObject:socketNumber]; 85 | } 86 | 87 | - (void) removeSocket:(NSNumber *)socketNumber { 88 | [_activeSocks removeObjectIdenticalTo:socketNumber]; 89 | } 90 | 91 | - (void) closeAllSockets { 92 | for (NSNumber *numberSocket in _activeSocks) { 93 | int sock = [numberSocket intValue]; 94 | close(sock); 95 | } 96 | } 97 | 98 | - (BOOL) start { 99 | _activeSocks = [[NSMutableArray alloc] init]; 100 | 101 | CFSocketContext ctx = {0, (void *) CFBridgingRetain(self), NULL, NULL, NULL}; 102 | _sock = CFSocketCreate(NULL, PF_INET6, SOCK_STREAM, IPPROTO_TCP, 103 | kCFSocketAcceptCallBack, (CFSocketCallBack)acceptCallBack, &ctx); 104 | if (_sock == NULL) { 105 | return NO; 106 | } 107 | 108 | int val = 1; 109 | setsockopt(CFSocketGetNative(_sock), SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)); 110 | 111 | struct sockaddr_in6 addr6; 112 | memset(&addr6, 0, sizeof(addr6)); 113 | addr6.sin6_len = sizeof(addr6); 114 | addr6.sin6_family = AF_INET6; 115 | addr6.sin6_port = htons(54295); 116 | addr6.sin6_flowinfo = 0; 117 | addr6.sin6_addr = in6addr_any; 118 | 119 | CFSocketError err = CFSocketSetAddress(_sock, (CFDataRef) [NSData dataWithBytes:&addr6 length:sizeof(addr6)]); 120 | if (err != kCFSocketSuccess) { 121 | CFSocketInvalidate(_sock); 122 | CFRelease(_sock); 123 | _sock = NULL; 124 | return NO; 125 | } 126 | 127 | CFRunLoopRef loop = CFRunLoopGetCurrent(); 128 | CFRunLoopSourceRef src = CFSocketCreateRunLoopSource(NULL, _sock, 0); 129 | CFRunLoopAddSource(loop, src, kCFRunLoopCommonModes); 130 | CFRelease(src); 131 | 132 | return YES; 133 | } 134 | 135 | - (BOOL) stop { 136 | [self closeAllSockets]; 137 | if (_sock != NULL) { 138 | CFSocketInvalidate(_sock); 139 | CFRelease(_sock); 140 | _sock = NULL; 141 | } 142 | return YES; 143 | } 144 | 145 | - (BOOL) isRunning { 146 | return _sock != NULL; 147 | } 148 | 149 | @end 150 | -------------------------------------------------------------------------------- /Source/Classes/MUMessagesDatabase.m: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2012 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | #import "MUMessagesDatabase.h" 6 | #import "MUTextMessage.h" 7 | #import "MUDataURL.h" 8 | 9 | #import 10 | 11 | #import 12 | 13 | @interface MUMessagesDatabase () { 14 | NSCache *_msgCache; 15 | FMDatabase *_db; 16 | NSInteger _count; 17 | } 18 | @end 19 | 20 | @implementation MUMessagesDatabase 21 | 22 | - (id) init { 23 | if ((self = [super init])) { 24 | NSFileManager *manager = [NSFileManager defaultManager]; 25 | NSString *directory = NSTemporaryDirectory(); 26 | NSString *dbPath = [directory stringByAppendingPathComponent:@"msg.db"]; 27 | [manager removeItemAtPath:dbPath error:nil]; 28 | _db = [[FMDatabase alloc] initWithPath:dbPath]; 29 | if (![_db open]) { 30 | NSLog(@"MUMessagesDatabse: Failed to open."); 31 | } 32 | 33 | [_db executeUpdate:@"CREATE TABLE IF NOT EXISTS `msg` " 34 | @"(`id` INTEGER PRIMARY KEY AUTOINCREMENT," 35 | @" `rendered` BLOB," 36 | @" `plist` BLOB)"]; 37 | 38 | _msgCache = [[NSCache alloc] init]; 39 | [_msgCache setCountLimit:10]; 40 | } 41 | return self; 42 | } 43 | 44 | - (void) addMessage:(MKTextMessage *)msg withHeading:(NSString *)heading andSentBySelf:(BOOL)selfSent { 45 | NSError *err = nil; 46 | NSString *plainMsg = [msg plainTextString]; 47 | plainMsg = [plainMsg stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; 48 | NSMutableArray *imageDataArray = [[NSMutableArray alloc] initWithCapacity:[[msg embeddedImages] count]]; 49 | for (NSString *dataUrl in [msg embeddedImages]) { 50 | NSData *imgData = [MUDataURL dataFromDataURL:dataUrl]; 51 | if (imgData) { 52 | [imageDataArray addObject:imgData]; 53 | } 54 | } 55 | 56 | NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys: 57 | heading, @"heading", 58 | plainMsg, @"msg", 59 | [NSDate date], @"date", 60 | [msg embeddedLinks], @"links", 61 | imageDataArray, @"images", 62 | [NSNumber numberWithBool:selfSent], @"selfsent", 63 | nil]; 64 | NSData *plist = [NSPropertyListSerialization dataWithPropertyList:dict format:NSPropertyListBinaryFormat_v1_0 options:0 error:&err]; 65 | [_db executeUpdate:@"INSERT INTO `msg` (`rendered`, `plist`) VALUES (?,?)", [NSNull null], plist ? plist : [NSNull null]]; 66 | _count++; 67 | } 68 | 69 | - (void) clearMessageAtIndex:(NSInteger)row { 70 | [_db executeUpdate:@"UPDATE `msg` SET `plist`=NULL, `rendered`=NULL WHERE `id`=?", [NSNumber numberWithInteger:row+1]]; 71 | [_msgCache removeObjectForKey:[NSNumber numberWithInteger:row+1]]; 72 | } 73 | 74 | - (MUTextMessage *) messageAtIndex:(NSInteger)row { 75 | MUTextMessage *txtMsg = [_msgCache objectForKey:[NSNumber numberWithInteger:row+1]]; 76 | if (txtMsg != nil) 77 | return txtMsg; 78 | 79 | FMResultSet *result = [_db executeQuery:@"SELECT `plist` FROM `msg` WHERE `id` = ?", [NSNumber numberWithInteger:row+1]]; 80 | if ([result next]) { 81 | NSData *plistData = [result dataForColumnIndex:0]; 82 | if (plistData) { 83 | NSDictionary *dict = [NSPropertyListSerialization propertyListWithData:plistData options:0 format:nil error:nil]; 84 | if (dict) { 85 | NSArray *imgDataArray = [dict objectForKey:@"images"]; 86 | NSMutableArray *imagesArray = [[NSMutableArray alloc] initWithCapacity:[imgDataArray count]]; 87 | for (NSData *data in imgDataArray) { 88 | [imagesArray addObject:[UIImage imageWithData:data]]; 89 | } 90 | txtMsg = [MUTextMessage textMessageWithHeading:[dict objectForKey:@"heading"] 91 | andMessage:[dict objectForKey:@"msg"] 92 | andEmbeddedLinks:[dict objectForKey:@"links"] 93 | andEmbeddedImages:imagesArray 94 | andTimestampDate:[dict objectForKey:@"date"] 95 | isSentBySelf:[[dict objectForKey:@"selfsent"] boolValue]]; 96 | [_msgCache setObject:txtMsg forKey:[NSNumber numberWithInteger:row+1]]; 97 | return txtMsg; 98 | } 99 | } 100 | } 101 | return nil; 102 | } 103 | 104 | - (NSInteger) count { 105 | return _count; 106 | } 107 | 108 | @end 109 | -------------------------------------------------------------------------------- /Source/Classes/MUCertificateController.m: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2010 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | #import "MUCertificateController.h" 6 | #import 7 | 8 | @implementation MUCertificateController 9 | 10 | // Retrieve a certificate by its persistent reference. 11 | // 12 | // If the value stored in the keychain is of type SecIdentityRef, the 13 | // returned MKCertificate will include both the certificate and the 14 | // private key of the returned identity. 15 | // 16 | // If the value stored in the keychain is of type SecCertificateRef, 17 | // the returned MKCertificate will not include a private key. 18 | + (MKCertificate *) certificateWithPersistentRef:(NSData *)persistentRef { 19 | NSDictionary *query = [NSDictionary dictionaryWithObjectsAndKeys: 20 | persistentRef, kSecValuePersistentRef, 21 | kCFBooleanTrue, kSecReturnRef, 22 | kSecMatchLimitOne, kSecMatchLimit, 23 | nil]; 24 | CFTypeRef thing = NULL; 25 | MKCertificate *cert = nil; 26 | if (SecItemCopyMatching((CFDictionaryRef)query, &thing) == noErr && thing != NULL) { 27 | CFTypeID receivedType = CFGetTypeID(thing); 28 | if (receivedType == SecIdentityGetTypeID()) { 29 | SecIdentityRef identity = (SecIdentityRef) thing; 30 | SecCertificateRef secCert = NULL; 31 | if (SecIdentityCopyCertificate(identity, &secCert) == noErr) { 32 | NSData *secData = (NSData *)SecCertificateCopyData(secCert); 33 | SecKeyRef secKey = NULL; 34 | if (SecIdentityCopyPrivateKey(identity, &secKey) == noErr) { 35 | NSData *pkeyData = nil; 36 | query = [NSDictionary dictionaryWithObjectsAndKeys: 37 | (CFTypeRef) secKey, kSecValueRef, 38 | kCFBooleanTrue, kSecReturnData, 39 | kSecMatchLimitOne, kSecMatchLimit, 40 | nil]; 41 | if (SecItemCopyMatching((CFDictionaryRef)query, (CFTypeRef *)&pkeyData) == noErr) { 42 | cert = [MKCertificate certificateWithCertificate:secData privateKey:pkeyData]; 43 | [pkeyData release]; 44 | } 45 | CFRelease(secKey); 46 | } 47 | [secData release]; 48 | } 49 | } else if (receivedType == SecCertificateGetTypeID()) { 50 | SecCertificateRef secCert = (SecCertificateRef) thing; 51 | NSData *secData = (NSData *)SecCertificateCopyData(secCert); 52 | cert = [MKCertificate certificateWithCertificate:secData privateKey:nil]; 53 | [secData release]; 54 | } else { 55 | return nil; 56 | } 57 | } 58 | return cert; 59 | } 60 | 61 | // Converts a hex string into a user-readable fingerprint. 62 | + (NSString *) fingerprintFromHexString:(NSString *)hexDigest { 63 | NSMutableString *fingerprint = [NSMutableString string]; 64 | for (int i = 0; i < [hexDigest length]; i++) { 65 | if ((i % 2) == 0 && i > 0 && i < hexDigest.length-1) { 66 | [fingerprint appendString:@":"]; 67 | } 68 | [fingerprint appendFormat:@"%C", [hexDigest characterAtIndex:i]]; 69 | } 70 | return fingerprint; 71 | } 72 | 73 | // Delete the certificate referenced by the persistent reference persistentRef. 74 | // todo(mkrautz): Don't leak OSStatus. 75 | + (OSStatus) deleteCertificateWithPersistentRef:(NSData *)persistentRef { 76 | // This goes against what the documentation says for this function, but Apple has stated that 77 | // this is the intended way to delete via a persistent ref through a rdar. 78 | NSDictionary *op = [NSDictionary dictionaryWithObjectsAndKeys: 79 | persistentRef, kSecValuePersistentRef, 80 | nil]; 81 | return SecItemDelete((CFDictionaryRef)op); 82 | } 83 | 84 | // Returns the certificate set as the default or 'active' certificate. 85 | + (MKCertificate *) defaultCertificate { 86 | NSData *persistentRef = [[NSUserDefaults standardUserDefaults] objectForKey:@"DefaultCertificate"]; 87 | return [MUCertificateController certificateWithPersistentRef:persistentRef]; 88 | } 89 | 90 | // Set the default certificate by its persistent ref. 91 | + (void) setDefaultCertificateByPersistentRef:(NSData *)persistentRef { 92 | [[NSUserDefaults standardUserDefaults] setObject:persistentRef forKey:@"DefaultCertificate"]; 93 | } 94 | 95 | // Returns an array of the persistent refs of all SecIdentityRefs 96 | // stored in the application's keychain. 97 | + (NSArray *) persistentRefsForIdentities { 98 | NSDictionary *query = @{ 99 | (id)kSecClass: (id)kSecClassIdentity, 100 | (id)kSecReturnPersistentRef: (id)kCFBooleanTrue, 101 | (id)kSecMatchLimit: (id)kSecMatchLimitAll 102 | }; 103 | NSArray *array = nil; 104 | OSStatus err = SecItemCopyMatching((CFDictionaryRef)query, (CFTypeRef *)&array); 105 | if (err != noErr) { 106 | [array release]; 107 | return nil; 108 | } 109 | 110 | return [array autorelease]; 111 | } 112 | 113 | @end 114 | -------------------------------------------------------------------------------- /Source/Classes/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /Source/Classes/MUImageViewController.m: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2012 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | #import "MUImageViewController.h" 6 | #import "MUColor.h" 7 | 8 | @interface MUImageViewController () { 9 | NSArray *_images; 10 | NSArray *_imageViews; 11 | UIScrollView *_scrollView; 12 | NSUInteger _curPage; 13 | } 14 | @end 15 | 16 | @implementation MUImageViewController 17 | 18 | - (id) initWithImages:(NSArray *)images { 19 | if ((self = [super init])) { 20 | _images = images; 21 | _curPage = 0; 22 | } 23 | return self; 24 | } 25 | 26 | - (void) viewDidLoad { 27 | [super viewDidLoad]; 28 | 29 | CGRect frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height-44); 30 | 31 | _scrollView = [[UIScrollView alloc] initWithFrame:frame]; 32 | [_scrollView setDelegate:self]; 33 | [_scrollView setPagingEnabled:YES]; 34 | [_scrollView setMaximumZoomScale:1.0f]; 35 | [_scrollView setMinimumZoomScale:1.0f]; 36 | [_scrollView setShowsVerticalScrollIndicator:NO]; 37 | [_scrollView setShowsHorizontalScrollIndicator:NO]; 38 | 39 | CGRect contentFrame = CGRectMake(0, 0, frame.size.width * [_images count], frame.size.height); 40 | [_scrollView setContentSize:contentFrame.size]; 41 | NSMutableArray *imageViews = [[NSMutableArray alloc] initWithCapacity:[_images count]]; 42 | 43 | NSUInteger i = 0; 44 | for (i = 0; i < [_images count]; i++) { 45 | CGRect imageFrame = CGRectMake(frame.size.width*i, 0, frame.size.width, frame.size.height); 46 | UIScrollView *imgZoomer = [[UIScrollView alloc] initWithFrame:imageFrame]; 47 | UIImageView *imgView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, imageFrame.size.width, imageFrame.size.height)]; 48 | [imgView setImage:[_images objectAtIndex:i]]; 49 | [imgView setContentMode:UIViewContentModeScaleAspectFit]; 50 | [imgZoomer setDelegate:self]; 51 | [imgZoomer addSubview:imgView]; 52 | [imgZoomer setMaximumZoomScale:4.0f]; 53 | [imgZoomer setMinimumZoomScale:1.0f]; 54 | [imgZoomer setShowsVerticalScrollIndicator:NO]; 55 | [imgZoomer setShowsHorizontalScrollIndicator:NO]; 56 | [_scrollView addSubview:imgZoomer]; 57 | [imageViews addObject:imgView]; 58 | ++i; 59 | } 60 | 61 | _imageViews = imageViews; 62 | 63 | [self.view addSubview:_scrollView]; 64 | } 65 | 66 | - (void) viewWillAppear:(BOOL)animated { 67 | [super viewWillAppear:animated]; 68 | 69 | self.navigationItem.title = [NSString stringWithFormat:NSLocalizedString(@"%lu of %lu", nil), (unsigned long)1, (unsigned long)[_images count]]; 70 | 71 | if (@available(iOS 7, *)) { 72 | _scrollView.backgroundColor = [MUColor backgroundViewiOS7Color]; 73 | } 74 | 75 | UIBarButtonItem *actionButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAction target:self action:@selector(actionClicked:)]; 76 | self.navigationItem.rightBarButtonItem = actionButton; 77 | } 78 | 79 | #pragma mark - UIScrollViewDelegate 80 | 81 | - (void) scrollViewDidScroll:(UIScrollView *)scrollView { 82 | if (scrollView == _scrollView) { 83 | CGPoint pt = [_scrollView contentOffset]; 84 | NSInteger pg = (NSInteger)(pt.x / self.view.frame.size.width); 85 | if (pg != _curPage) { 86 | _curPage = pg; 87 | self.navigationItem.title = [NSString stringWithFormat:NSLocalizedString(@"%lu of %lu", nil), (unsigned long)1+_curPage, (unsigned long)[_images count]]; 88 | } 89 | } 90 | } 91 | 92 | - (UIView *) viewForZoomingInScrollView:(UIScrollView *)scrollView { 93 | if (scrollView != _scrollView) { 94 | return [_imageViews objectAtIndex:_curPage]; 95 | } 96 | return nil; 97 | } 98 | 99 | #pragma mark - Actions 100 | 101 | - (void) image:(UIImage *)img didFinishSavingWithError:(NSError *)err contextInfo:(void *)userInfo { 102 | if (err != nil) { 103 | UIAlertController* alertCtrl = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"Unable to save image", nil) 104 | message:[err description] 105 | preferredStyle:UIAlertControllerStyleAlert]; 106 | [alertCtrl addAction: [UIAlertAction actionWithTitle:NSLocalizedString(@"OK", nil) 107 | style:UIAlertActionStyleCancel 108 | handler:nil]]; 109 | 110 | [self presentViewController:alertCtrl animated:YES completion:nil]; 111 | } 112 | } 113 | 114 | - (void) actionClicked:(id)sender { 115 | UIAlertController* alertCtrl = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"Export Image", nil) 116 | message:nil 117 | preferredStyle:UIAlertControllerStyleActionSheet]; 118 | [alertCtrl addAction: [UIAlertAction actionWithTitle:NSLocalizedString(@"Cancel", nil) 119 | style:UIAlertActionStyleCancel 120 | handler:nil]]; 121 | [alertCtrl addAction: [UIAlertAction actionWithTitle:NSLocalizedString(@"Export to Photos", nil) 122 | style:UIAlertActionStyleDefault 123 | handler:^(UIAlertAction * _Nonnull action) { 124 | UIImageWriteToSavedPhotosAlbum([self->_images objectAtIndex:self->_curPage], self, @selector(image:didFinishSavingWithError:contextInfo:), NULL); 125 | }]]; 126 | 127 | [self presentViewController:alertCtrl animated:YES completion:nil]; 128 | } 129 | 130 | @end 131 | -------------------------------------------------------------------------------- /Source/Classes/MUServerCell.m: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2011 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | #import "MUServerCell.h" 6 | #import "MUColor.h" 7 | #import "MUFavouriteServer.h" 8 | 9 | @interface MUServerCell () { 10 | NSString *_displayname; 11 | NSString *_hostname; 12 | NSString *_port; 13 | NSString *_username; 14 | MKServerPinger *_pinger; 15 | } 16 | - (UIImage *) drawPingImageWithPingValue:(NSUInteger)pingMs andUserCount:(NSUInteger)userCount isFull:(BOOL)isFull; 17 | @end 18 | 19 | @implementation MUServerCell 20 | 21 | + (NSString *) reuseIdentifier { 22 | return @"ServerCell"; 23 | } 24 | 25 | - (id) init { 26 | return [super initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:[MUServerCell reuseIdentifier]]; 27 | } 28 | 29 | - (void) populateFromDisplayName:(NSString *)displayName hostName:(NSString *)hostName port:(NSString *)port { 30 | _displayname = [displayName copy]; 31 | 32 | _port = [port copy]; 33 | 34 | _pinger = nil; 35 | 36 | if ([hostName length] > 0) { 37 | _hostname = [hostName copy]; 38 | _pinger = [[MKServerPinger alloc] initWithHostname:_hostname port:_port]; 39 | [_pinger setDelegate:self]; 40 | } else { 41 | _hostname = NSLocalizedString(@"(No Server)", nil); 42 | } 43 | 44 | self.textLabel.text = _displayname; 45 | self.detailTextLabel.text = [NSString stringWithFormat:@"%@:%@", _hostname, _port]; 46 | self.imageView.image = [self drawPingImageWithPingValue:999 andUserCount:0 isFull:NO]; 47 | } 48 | 49 | - (void) populateFromFavouriteServer:(MUFavouriteServer *)favServ { 50 | _displayname = [[favServ displayName] copy]; 51 | 52 | _hostname = [[favServ hostName] copy]; 53 | 54 | _port = [NSString stringWithFormat:@"%lu", (unsigned long)[favServ port]]; 55 | 56 | if ([[favServ userName] length] > 0) { 57 | _username = [[favServ userName] copy]; 58 | } else { 59 | _username = [[[NSUserDefaults standardUserDefaults] objectForKey:@"DefaultUserName"] copy]; 60 | } 61 | 62 | _pinger = nil; 63 | if ([_hostname length] > 0) { 64 | _pinger = [[MKServerPinger alloc] initWithHostname:_hostname port:_port]; 65 | [_pinger setDelegate:self]; 66 | } else { 67 | _hostname = NSLocalizedString(@"(No Server)", nil); 68 | } 69 | 70 | self.textLabel.text = _displayname; 71 | self.detailTextLabel.text = [NSString stringWithFormat:NSLocalizedString(@"%@ on %@:%@", @"username on hostname:port"), 72 | _username, _hostname, _port]; 73 | self.imageView.image = [self drawPingImageWithPingValue:999 andUserCount:0 isFull:NO]; 74 | } 75 | 76 | - (void) setSelected:(BOOL)selected animated:(BOOL)animated { 77 | [super setSelected:selected animated:animated]; 78 | } 79 | 80 | - (UIImage *) drawPingImageWithPingValue:(NSUInteger)pingMs andUserCount:(NSUInteger)userCount isFull:(BOOL)isFull { 81 | UIImage *img = nil; 82 | 83 | UIColor *pingColor = [MUColor badPingColor]; 84 | if (pingMs <= 125) 85 | pingColor = [MUColor goodPingColor]; 86 | else if (pingMs > 125 && pingMs <= 250) 87 | pingColor = [MUColor mediumPingColor]; 88 | else if (pingMs > 250) 89 | pingColor = [MUColor badPingColor]; 90 | NSString *pingStr = [NSString stringWithFormat:@"%lu\nms", (unsigned long)pingMs]; 91 | if (pingMs >= 999) 92 | pingStr = @"∞\nms"; 93 | 94 | UIGraphicsBeginImageContextWithOptions(CGSizeMake(66.0f, 32.0f), NO, [[UIScreen mainScreen] scale]); 95 | CGContextRef ctx = UIGraphicsGetCurrentContext(); 96 | CGContextSetFillColorWithColor(ctx, pingColor.CGColor); 97 | CGContextFillRect(ctx, CGRectMake(0, 0, 32.0, 32.0)); 98 | 99 | CGContextSetTextDrawingMode(ctx, kCGTextFill); 100 | CGContextSetFillColorWithColor(ctx, [UIColor whiteColor].CGColor); 101 | NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init]; 102 | paragraphStyle.lineBreakMode = NSLineBreakByTruncatingTail; 103 | paragraphStyle.alignment = NSTextAlignmentCenter; 104 | [pingStr drawInRect:CGRectMake(0.0, 0.0, 32.0, 32.0) withAttributes:@{ 105 | NSFontAttributeName : [UIFont boldSystemFontOfSize: 12], 106 | NSParagraphStyleAttributeName : paragraphStyle, 107 | NSForegroundColorAttributeName : [UIColor whiteColor] 108 | }]; 109 | 110 | if (!isFull) { 111 | // Non-full servers get the mild iOS blue color 112 | CGContextSetFillColorWithColor(ctx, [MUColor userCountColor].CGColor); 113 | } else { 114 | // Mark full servers with the same red as we use for 115 | // 'bad' pings... 116 | CGContextSetFillColorWithColor(ctx, [MUColor badPingColor].CGColor); 117 | } 118 | CGContextFillRect(ctx, CGRectMake(34.0, 0, 32.0, 32.0)); 119 | 120 | CGContextSetTextDrawingMode(ctx, kCGTextFill); 121 | CGContextSetFillColorWithColor(ctx, [UIColor whiteColor].CGColor); 122 | NSString *usersStr = [NSString stringWithFormat:NSLocalizedString(@"%lu\nppl", @"user count"), (unsigned long)userCount]; 123 | paragraphStyle = [[NSMutableParagraphStyle alloc] init]; 124 | paragraphStyle.lineBreakMode = NSLineBreakByTruncatingTail; 125 | paragraphStyle.alignment = NSTextAlignmentCenter; 126 | [usersStr drawInRect:CGRectMake(34.0, 0.0, 32.0, 32.0) withAttributes:@{ 127 | NSFontAttributeName : [UIFont boldSystemFontOfSize: 12], 128 | NSParagraphStyleAttributeName : paragraphStyle, 129 | NSForegroundColorAttributeName : [UIColor whiteColor] 130 | }]; 131 | 132 | img = UIGraphicsGetImageFromCurrentImageContext(); 133 | UIGraphicsEndImageContext(); 134 | 135 | return img; 136 | } 137 | 138 | - (void) serverPingerResult:(MKServerPingerResult *)result { 139 | NSUInteger pingValue = (NSUInteger)(result->ping * 1000.0f); 140 | NSUInteger userCount = (NSUInteger)(result->cur_users); 141 | BOOL isFull = result->cur_users == result->max_users; 142 | self.imageView.image = [self drawPingImageWithPingValue:pingValue andUserCount:userCount isFull:isFull]; 143 | } 144 | 145 | @end 146 | -------------------------------------------------------------------------------- /Source/Classes/MUAudioQualityPreferencesViewController.m: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2011 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | #import "MUAudioQualityPreferencesViewController.h" 6 | #import "MUTableViewHeaderLabel.h" 7 | #import "MUColor.h" 8 | #import "MUImage.h" 9 | #import "MUBackgroundView.h" 10 | 11 | @implementation MUAudioQualityPreferencesViewController 12 | 13 | - (id) init { 14 | if ((self = [super initWithStyle:UITableViewStyleGrouped])) { 15 | self.preferredContentSize = CGSizeMake(320, 480); 16 | } 17 | return self; 18 | } 19 | 20 | - (void) viewWillAppear:(BOOL)animated { 21 | [super viewWillAppear:animated]; 22 | 23 | self.title = NSLocalizedString(@"Audio Quality", nil); 24 | 25 | self.tableView.backgroundView = [MUBackgroundView backgroundView]; 26 | 27 | if (@available(iOS 7, *)) { 28 | self.tableView.separatorStyle = UITableViewCellSeparatorStyleSingleLine; 29 | self.tableView.separatorInset = UIEdgeInsetsZero; 30 | } else { 31 | self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone; 32 | } 33 | 34 | self.tableView.scrollEnabled = NO; 35 | } 36 | 37 | #pragma mark - Table view data source 38 | 39 | - (NSInteger) numberOfSectionsInTableView:(UITableView *)tableView { 40 | return 1; 41 | } 42 | 43 | - (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 44 | return 3; 45 | } 46 | 47 | - (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 48 | static NSString *CellIdentifier = @"MUAudioQualityPreferencesCell"; 49 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 50 | if (cell == nil) { 51 | cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier]; 52 | } 53 | 54 | NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; 55 | 56 | cell.selectionStyle = UITableViewCellSelectionStyleGray; 57 | cell.accessoryView = nil; 58 | 59 | if ([indexPath section] == 0) { 60 | if ([indexPath row] == 0) { 61 | cell.textLabel.text = NSLocalizedString(@"Low", nil); 62 | cell.detailTextLabel.text = NSLocalizedString(@"16 kbit/s, 60 ms audio per packet", nil); 63 | if ([[defaults stringForKey:@"AudioQualityKind"] isEqualToString:@"low"]) { 64 | cell.accessoryView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"GrayCheckmark"]]; 65 | cell.textLabel.textColor = [MUColor selectedTextColor]; 66 | } 67 | } else if ([indexPath row] == 1) { 68 | cell.textLabel.text = NSLocalizedString(@"Balanced", nil); 69 | cell.detailTextLabel.text = NSLocalizedString(@"40 kbit/s, 20 ms audio per packet", nil); 70 | if ([[defaults stringForKey:@"AudioQualityKind"] isEqualToString:@"balanced"]) { 71 | cell.accessoryView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"GrayCheckmark"]]; 72 | cell.textLabel.textColor = [MUColor selectedTextColor]; 73 | } 74 | } else if ([indexPath row] == 2) { 75 | cell.textLabel.text = NSLocalizedString(@"High", nil); 76 | cell.detailTextLabel.text = NSLocalizedString(@"72 kbit/s, 10 ms audio per packet", nil); 77 | if ([[defaults stringForKey:@"AudioQualityKind"] isEqualToString:@"high"]) { 78 | cell.accessoryView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"GrayCheckmark"]]; 79 | cell.textLabel.textColor = [MUColor selectedTextColor]; 80 | } 81 | } else if ([indexPath row] == 3) { 82 | cell.textLabel.text = NSLocalizedString(@"Custom", nil); 83 | cell.detailTextLabel.text = nil; 84 | if ([[defaults stringForKey:@"AudioQualityKind"] isEqualToString:@"custom"]) { 85 | cell.accessoryView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"GrayCheckmark"]]; 86 | cell.textLabel.textColor = [MUColor selectedTextColor]; 87 | } 88 | } 89 | } 90 | 91 | return cell; 92 | } 93 | 94 | - (UIView *) tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { 95 | if (section == 0) { // Input 96 | return [MUTableViewHeaderLabel labelWithText:NSLocalizedString(@"Quality Presets", nil)]; 97 | } else if (section == 1) { 98 | return [MUTableViewHeaderLabel labelWithText:NSLocalizedString(@"Custom Quality", nil)]; 99 | } else { 100 | return nil; 101 | } 102 | } 103 | 104 | - (CGFloat) tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section { 105 | if (section == 0) { 106 | return [MUTableViewHeaderLabel defaultHeaderHeight]; 107 | } else if (section == 1) { 108 | return [MUTableViewHeaderLabel defaultHeaderHeight]; 109 | } 110 | return 0.0f; 111 | } 112 | 113 | #pragma mark - Table view delegate 114 | 115 | - (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 116 | [self.tableView deselectRowAtIndexPath:indexPath animated:YES]; 117 | UITableViewCell *cell = nil; 118 | int nsects = 3; 119 | for (int i = 0; i <= nsects; i++) { 120 | cell = [self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:i inSection:0]]; 121 | cell.accessoryView = nil; 122 | cell.textLabel.textColor = [UIColor blackColor]; 123 | } 124 | cell = [self.tableView cellForRowAtIndexPath:indexPath]; 125 | cell.accessoryView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"GrayCheckmark"]]; 126 | cell.textLabel.textColor = [MUColor selectedTextColor]; 127 | NSString *val = nil; 128 | switch ([indexPath row]) { 129 | case 0: val = @"low"; break; 130 | case 1: val = @"balanced"; break; 131 | case 2: val = @"high"; break; 132 | case 3: val = @"custom"; break; 133 | } 134 | if (val != nil) 135 | [[NSUserDefaults standardUserDefaults] setObject:val forKey:@"AudioQualityKind"]; 136 | } 137 | 138 | @end 139 | -------------------------------------------------------------------------------- /Source/Classes/MUCertificateCreationProgressView.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 48 | 49 | 50 | 51 | 52 | 61 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /Source/Classes/MUPublicServerList.m: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2010 The 'Mumble for iOS' Developers. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | #import "MUPublicServerList.h" 6 | #import 7 | 8 | @interface MUPublicServerList () { 9 | NSData *_serverListXML; 10 | NSMutableDictionary *_continentCountries; 11 | NSMutableDictionary *_countryServers; 12 | NSDictionary *_continentNames; 13 | NSDictionary *_countryNames; 14 | NSMutableArray *_modelContinents; 15 | NSMutableArray *_modelCountries; 16 | BOOL _parsed; 17 | } 18 | + (NSString *) filePath; 19 | @end 20 | 21 | @interface MUPublicServerListFetcher () {} 22 | @end 23 | 24 | @implementation MUPublicServerListFetcher 25 | 26 | - (id) init { 27 | if ((self = [super init])) { 28 | // ... 29 | } 30 | return self; 31 | } 32 | 33 | - (void) attemptUpdate { 34 | NSURLRequest *req = [NSURLRequest requestWithURL:[MKServices regionalServerListURL]]; 35 | [[NSURLSession sharedSession] dataTaskWithRequest:req completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { 36 | if (error || data == nil) { 37 | return; 38 | } 39 | 40 | [data writeToFile:[MUPublicServerList filePath] atomically:YES]; 41 | }]; 42 | } 43 | 44 | @end 45 | 46 | 47 | @implementation MUPublicServerList 48 | 49 | + (NSString *) filePath { 50 | NSArray *documentDirectories = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, 51 | NSUserDomainMask, 52 | YES); 53 | NSString *directory = [documentDirectories objectAtIndex:0]; 54 | [[NSFileManager defaultManager] createDirectoryAtPath:directory withIntermediateDirectories:YES attributes:nil error:nil]; 55 | return [directory stringByAppendingPathComponent:@"publist.xml"]; 56 | } 57 | 58 | - (id) init { 59 | if ((self = [super init])) { 60 | if ([[NSFileManager defaultManager] fileExistsAtPath:[MUPublicServerList filePath]]) { 61 | _serverListXML = [[NSData alloc] initWithContentsOfFile:[MUPublicServerList filePath]]; 62 | } else { 63 | _serverListXML = [[NSData alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"publist" ofType:@"xml"]]; 64 | } 65 | 66 | _continentNames = [[NSDictionary alloc] initWithContentsOfFile: [NSString stringWithFormat:@"%@/Continents.plist", [[NSBundle mainBundle] resourcePath]]]; 67 | _countryNames = [[NSDictionary alloc] initWithContentsOfFile: [NSString stringWithFormat:@"%@/Countries.plist", [[NSBundle mainBundle] resourcePath]]]; 68 | } 69 | return self; 70 | } 71 | 72 | - (void) parse { 73 | // Job's done. 74 | if (_parsed) 75 | return; 76 | 77 | _continentCountries = [[NSMutableDictionary alloc] initWithCapacity:[_continentNames count]]; 78 | _countryServers = [[NSMutableDictionary alloc] init]; 79 | 80 | // Parse XML server list 81 | NSXMLParser *parser = [[NSXMLParser alloc] initWithData:_serverListXML]; 82 | [parser setDelegate:(id)self]; 83 | [parser parse]; 84 | 85 | // Transform from NSDictionary representation to a NSArray-model 86 | NSArray *continentCodes = [[_continentNames allKeys] sortedArrayUsingSelector:@selector(compare:)]; 87 | _modelContinents = [[NSMutableArray alloc] initWithCapacity:[continentCodes count]]; 88 | _modelCountries = [[NSMutableArray alloc] init]; 89 | 90 | for (NSString *key in continentCodes) { 91 | [_modelContinents addObject:[_continentNames objectForKey:key]]; 92 | 93 | NSSet *countryCodeSet = [_continentCountries objectForKey:key]; 94 | NSArray *countryCodes = [[countryCodeSet allObjects] sortedArrayUsingSelector:@selector(compare:)]; 95 | 96 | NSMutableArray *countries = [NSMutableArray arrayWithCapacity:[countryCodes count]]; 97 | 98 | for (NSString *countryKey in countryCodes) { 99 | NSString *countryName = [_countryNames objectForKey:countryKey]; 100 | NSArray *countryServerList = [_countryServers objectForKey:countryKey]; 101 | NSDictionary *country = [NSDictionary dictionaryWithObjectsAndKeys: 102 | countryName, @"name", 103 | countryServerList, @"servers", nil]; 104 | [countries addObject:country]; 105 | } 106 | [_modelCountries addObject:countries]; 107 | } 108 | 109 | _continentCountries = nil; 110 | _countryServers = nil; 111 | _parsed = YES; 112 | } 113 | 114 | #pragma mark - 115 | #pragma mark NSXMLParserDelegate methods 116 | 117 | - (void) parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict { 118 | if ([elementName isEqualToString:@"server"]) { 119 | NSString *countryCode = [attributeDict objectForKey:@"country_code"]; 120 | if (countryCode) { 121 | // Get server array for this particular country 122 | NSMutableArray *array = [_countryServers objectForKey:countryCode]; 123 | if (array == nil) { 124 | // No array available. Create a new one. 125 | array = [NSMutableArray arrayWithCapacity:50]; 126 | [_countryServers setObject:array forKey:countryCode]; 127 | } 128 | // Add attribute dict to server array. 129 | [array addObject:attributeDict]; 130 | 131 | // Extract the continent code of the country 132 | NSString *continentCode = [attributeDict objectForKey:@"continent_code"]; 133 | // Get our country set from our continent -> countries mapping 134 | NSMutableSet *countries = [_continentCountries objectForKey:continentCode]; 135 | if (countries == nil) { 136 | // No set for continent? Create a new one. 137 | countries = [NSMutableSet setWithCapacity:100]; 138 | [_continentCountries setObject:countries forKey:continentCode]; 139 | } 140 | [countries addObject:countryCode]; 141 | } 142 | } 143 | } 144 | 145 | - (void)parserDidEndDocument:(NSXMLParser *)parser { 146 | } 147 | 148 | #pragma mark - 149 | #pragma mark Model access 150 | 151 | // Returns the number of continents in the public server list 152 | - (NSInteger) numberOfContinents { 153 | return [_continentNames count]; 154 | } 155 | 156 | // Get continent at index 'idx'. 157 | - (NSString *) continentNameAtIndex:(NSInteger)index { 158 | return [_modelContinents objectAtIndex:index]; 159 | } 160 | 161 | // Get the number of countries in the continent at index 'idx'. 162 | - (NSInteger) numberOfCountriesAtContinentIndex:(NSInteger)index { 163 | return [[_modelCountries objectAtIndex:index] count]; 164 | } 165 | 166 | // Get a dictionary representing a country. 167 | - (NSDictionary *) countryAtIndexPath:(NSIndexPath *)indexPath { 168 | return [[_modelCountries objectAtIndex:[indexPath indexAtPosition:0]] objectAtIndex:[indexPath indexAtPosition:1]]; 169 | } 170 | 171 | // Return whether or not the server list has already been parsed 172 | - (BOOL) isParsed { 173 | return _parsed; 174 | } 175 | 176 | @end 177 | --------------------------------------------------------------------------------