commit 504c859ffaeef49d57eece4b712392b8d0003747 Author: Jonathan Schleifer Date: Tue Mar 22 02:37:47 2011 +0000 Initial import. FossilOrigin-Name: ba81f6810553036e35811b67461234f9cbac69c064114a89edd073c20b8fa656 diff --git a/Info.plist b/Info.plist new file mode 100644 index 0000000..dd97f90 --- /dev/null +++ b/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + org.webkeks.${PRODUCT_NAME:rfc1034identifier} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + OIRC + CFBundleVersion + 1 + + diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..54e2e18 --- /dev/null +++ b/Makefile @@ -0,0 +1,7 @@ +all: + cd src && ${MAKE} ${MFLAGS} + cd tests && ${MAKE} ${MFLAGS} + +clean: + cd src && ${MAKE} ${MFLAGS} clean + cd tests && ${MAKE} ${MFLAGS} clean diff --git a/ObjIRC.xcodeproj/project.pbxproj b/ObjIRC.xcodeproj/project.pbxproj new file mode 100644 index 0000000..b5fe5f1 --- /dev/null +++ b/ObjIRC.xcodeproj/project.pbxproj @@ -0,0 +1,397 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 4BBE6ECC1338258D007EE595 /* IRCChannel.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BBE6EC81338258D007EE595 /* IRCChannel.h */; }; + 4BBE6ECD1338258D007EE595 /* IRCChannel.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BBE6EC91338258D007EE595 /* IRCChannel.m */; }; + 4BBE6ECE1338258D007EE595 /* IRCConnection.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BBE6ECA1338258D007EE595 /* IRCConnection.h */; }; + 4BBE6ECF1338258D007EE595 /* IRCConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BBE6ECB1338258D007EE595 /* IRCConnection.m */; }; + 4BBE6EE313382DAE007EE595 /* IRCUser.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BBE6EE113382DAE007EE595 /* IRCUser.h */; }; + 4BBE6EE413382DAE007EE595 /* IRCUser.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BBE6EE213382DAE007EE595 /* IRCUser.m */; }; + 4BBE6EFA133836A8007EE595 /* ObjIRC.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4BBE6EB013382479007EE595 /* ObjIRC.framework */; }; + 4BBE6EFD133836CC007EE595 /* test.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BBE6EFB133836C2007EE595 /* test.m */; }; + 4BBE6EFF133839F1007EE595 /* ObjFW.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4BBE6EFE133839F1007EE595 /* ObjFW.framework */; }; + 4BBE6F0113383A06007EE595 /* ObjFW.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4BBE6F0013383A06007EE595 /* ObjFW.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 4BBE6EF613383686007EE595 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4BBE6EA613382479007EE595 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 4BBE6EAF13382479007EE595; + remoteInfo = ObjIRC; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 4BBE6EE713383659007EE595 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 4BBE6EB013382479007EE595 /* ObjIRC.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ObjIRC.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 4BBE6EC713382541007EE595 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = SOURCE_ROOT; }; + 4BBE6EC81338258D007EE595 /* IRCChannel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IRCChannel.h; path = src/IRCChannel.h; sourceTree = SOURCE_ROOT; }; + 4BBE6EC91338258D007EE595 /* IRCChannel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = IRCChannel.m; path = src/IRCChannel.m; sourceTree = SOURCE_ROOT; }; + 4BBE6ECA1338258D007EE595 /* IRCConnection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IRCConnection.h; path = src/IRCConnection.h; sourceTree = SOURCE_ROOT; }; + 4BBE6ECB1338258D007EE595 /* IRCConnection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = IRCConnection.m; path = src/IRCConnection.m; sourceTree = SOURCE_ROOT; }; + 4BBE6EE113382DAE007EE595 /* IRCUser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IRCUser.h; path = src/IRCUser.h; sourceTree = SOURCE_ROOT; }; + 4BBE6EE213382DAE007EE595 /* IRCUser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = IRCUser.m; path = src/IRCUser.m; sourceTree = SOURCE_ROOT; }; + 4BBE6EE913383659007EE595 /* Tests */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = Tests; sourceTree = BUILT_PRODUCTS_DIR; }; + 4BBE6EFB133836C2007EE595 /* test.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = test.m; path = tests/test.m; sourceTree = SOURCE_ROOT; }; + 4BBE6EFE133839F1007EE595 /* ObjFW.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ObjFW.framework; path = Library/Frameworks/ObjFW.framework; sourceTree = SDKROOT; }; + 4BBE6F0013383A06007EE595 /* ObjFW.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ObjFW.framework; path = Library/Frameworks/ObjFW.framework; sourceTree = SDKROOT; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 4BBE6EAC13382479007EE595 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 4BBE6F0113383A06007EE595 /* ObjFW.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 4BBE6EE613383659007EE595 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 4BBE6EFF133839F1007EE595 /* ObjFW.framework in Frameworks */, + 4BBE6EFA133836A8007EE595 /* ObjIRC.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 4BBE6EA413382479007EE595 = { + isa = PBXGroup; + children = ( + 4BBE6EB913382479007EE595 /* ObjIRC */, + 4BBE6EED13383659007EE595 /* Tests */, + 4BBE6EB113382479007EE595 /* Products */, + ); + sourceTree = ""; + }; + 4BBE6EB113382479007EE595 /* Products */ = { + isa = PBXGroup; + children = ( + 4BBE6EE913383659007EE595 /* Tests */, + ); + name = Products; + sourceTree = ""; + }; + 4BBE6EB213382479007EE595 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 4BBE6F0013383A06007EE595 /* ObjFW.framework */, + 4BBE6EB013382479007EE595 /* ObjIRC.framework */, + ); + name = Frameworks; + path = ..; + sourceTree = ""; + }; + 4BBE6EB913382479007EE595 /* ObjIRC */ = { + isa = PBXGroup; + children = ( + 4BBE6F0213383A19007EE595 /* Frameworks */, + 4BBE6EBA1338247A007EE595 /* Supporting Files */, + 4BBE6EC81338258D007EE595 /* IRCChannel.h */, + 4BBE6EC91338258D007EE595 /* IRCChannel.m */, + 4BBE6ECA1338258D007EE595 /* IRCConnection.h */, + 4BBE6ECB1338258D007EE595 /* IRCConnection.m */, + 4BBE6EE113382DAE007EE595 /* IRCUser.h */, + 4BBE6EE213382DAE007EE595 /* IRCUser.m */, + ); + path = ObjIRC; + sourceTree = ""; + }; + 4BBE6EBA1338247A007EE595 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 4BBE6EC713382541007EE595 /* Info.plist */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + 4BBE6EED13383659007EE595 /* Tests */ = { + isa = PBXGroup; + children = ( + 4BBE6EB213382479007EE595 /* Frameworks */, + 4BBE6EFB133836C2007EE595 /* test.m */, + ); + path = Tests; + sourceTree = ""; + }; + 4BBE6F0213383A19007EE595 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 4BBE6EFE133839F1007EE595 /* ObjFW.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 4BBE6EAD13382479007EE595 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 4BBE6ECC1338258D007EE595 /* IRCChannel.h in Headers */, + 4BBE6ECE1338258D007EE595 /* IRCConnection.h in Headers */, + 4BBE6EE313382DAE007EE595 /* IRCUser.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 4BBE6EAF13382479007EE595 /* ObjIRC */ = { + isa = PBXNativeTarget; + buildConfigurationList = 4BBE6EC21338247A007EE595 /* Build configuration list for PBXNativeTarget "ObjIRC" */; + buildPhases = ( + 4BBE6EAB13382479007EE595 /* Sources */, + 4BBE6EAC13382479007EE595 /* Frameworks */, + 4BBE6EAD13382479007EE595 /* Headers */, + 4BBE6EAE13382479007EE595 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = ObjIRC; + productName = ObjIRC; + productReference = 4BBE6EB013382479007EE595 /* ObjIRC.framework */; + productType = "com.apple.product-type.framework"; + }; + 4BBE6EE813383659007EE595 /* Tests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 4BBE6EF313383659007EE595 /* Build configuration list for PBXNativeTarget "Tests" */; + buildPhases = ( + 4BBE6EE513383659007EE595 /* Sources */, + 4BBE6EE613383659007EE595 /* Frameworks */, + 4BBE6EE713383659007EE595 /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + 4BBE6EF713383686007EE595 /* PBXTargetDependency */, + ); + name = Tests; + productName = Tests; + productReference = 4BBE6EE913383659007EE595 /* Tests */; + productType = "com.apple.product-type.tool"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 4BBE6EA613382479007EE595 /* Project object */ = { + isa = PBXProject; + buildConfigurationList = 4BBE6EA913382479007EE595 /* Build configuration list for PBXProject "ObjIRC" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = 4BBE6EA413382479007EE595; + productRefGroup = 4BBE6EB113382479007EE595 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 4BBE6EE813383659007EE595 /* Tests */, + 4BBE6EAF13382479007EE595 /* ObjIRC */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 4BBE6EAE13382479007EE595 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 4BBE6EAB13382479007EE595 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 4BBE6ECD1338258D007EE595 /* IRCChannel.m in Sources */, + 4BBE6ECF1338258D007EE595 /* IRCConnection.m in Sources */, + 4BBE6EE413382DAE007EE595 /* IRCUser.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 4BBE6EE513383659007EE595 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 4BBE6EFD133836CC007EE595 /* test.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 4BBE6EF713383686007EE595 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 4BBE6EAF13382479007EE595 /* ObjIRC */; + targetProxy = 4BBE6EF613383686007EE595 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 4BBE6EC01338247A007EE595 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = DEBUG; + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_VERSION = 4.2; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.6; + ONLY_ACTIVE_ARCH = YES; + OTHER_CFLAGS = ( + "-fconstant-string-class=OFConstantString", + "-fno-constant-cfstrings", + ); + SDKROOT = macosx; + WARNING_CFLAGS = ( + "-Wall", + "-Werror", + ); + }; + name = Debug; + }; + 4BBE6EC11338247A007EE595 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_VERSION = 4.2; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.6; + OTHER_CFLAGS = ( + "-fconstant-string-class=OFConstantString", + "-fno-constant-cfstrings", + ); + SDKROOT = macosx; + WARNING_CFLAGS = ( + "-Wall", + "-Werror", + ); + }; + name = Release; + }; + 4BBE6EC31338247A007EE595 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + COPY_PHASE_STRIP = NO; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + FRAMEWORK_VERSION = A; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_OBJC_EXCEPTIONS = YES; + GCC_VERSION = 4.2; + INFOPLIST_FILE = Info.plist; + PRODUCT_NAME = "$(TARGET_NAME)"; + WRAPPER_EXTENSION = framework; + }; + name = Debug; + }; + 4BBE6EC41338247A007EE595 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + FRAMEWORK_VERSION = A; + GCC_ENABLE_OBJC_EXCEPTIONS = YES; + GCC_VERSION = 4.2; + INFOPLIST_FILE = Info.plist; + PRODUCT_NAME = "$(TARGET_NAME)"; + WRAPPER_EXTENSION = framework; + }; + name = Release; + }; + 4BBE6EF413383659007EE595 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + COPY_PHASE_STRIP = NO; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_OBJC_EXCEPTIONS = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 4BBE6EF513383659007EE595 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + GCC_ENABLE_OBJC_EXCEPTIONS = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 4BBE6EA913382479007EE595 /* Build configuration list for PBXProject "ObjIRC" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 4BBE6EC01338247A007EE595 /* Debug */, + 4BBE6EC11338247A007EE595 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 4BBE6EC21338247A007EE595 /* Build configuration list for PBXNativeTarget "ObjIRC" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 4BBE6EC31338247A007EE595 /* Debug */, + 4BBE6EC41338247A007EE595 /* Release */, + ); + defaultConfigurationIsVisible = 0; + }; + 4BBE6EF313383659007EE595 /* Build configuration list for PBXNativeTarget "Tests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 4BBE6EF413383659007EE595 /* Debug */, + 4BBE6EF513383659007EE595 /* Release */, + ); + defaultConfigurationIsVisible = 0; + }; +/* End XCConfigurationList section */ + }; + rootObject = 4BBE6EA613382479007EE595 /* Project object */; +} diff --git a/src/IRCChannel.h b/src/IRCChannel.h new file mode 100644 index 0000000..e833c8a --- /dev/null +++ b/src/IRCChannel.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2010, 2011, Jonathan Schleifer + * + * https://webkeks.org/hg/objirc/ + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#import + +@class OFString; + +@interface IRCChannel: OFObject +{ + OFString *name; +} + +@property (readonly) OFString *name; + ++ channelWithName: (OFString*)name; +- initWithName: (OFString*)name; +@end diff --git a/src/IRCChannel.m b/src/IRCChannel.m new file mode 100644 index 0000000..16162ee --- /dev/null +++ b/src/IRCChannel.m @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2010, 2011, Jonathan Schleifer + * + * https://webkeks.org/hg/objirc/ + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#import "IRCChannel.h" + +@implementation IRCChannel +@synthesize name; + ++ channelWithName: (OFString*)name +{ + return [[[self alloc] initWithName: name] autorelease]; +} + +- initWithName: (OFString*)name_ +{ + self = [super init]; + + @try { + name = [name_ copy]; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ + [name release]; + + [super dealloc]; +} +@end diff --git a/src/IRCConnection.h b/src/IRCConnection.h new file mode 100644 index 0000000..b354d8c --- /dev/null +++ b/src/IRCConnection.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2010, 2011, Jonathan Schleifer + * + * https://webkeks.org/hg/objirc/ + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#import + +@class OFString; +@class OFMutableDictionary; +@class OFTCPSocket; +@class IRCConnection; +@class IRCUser; +@class IRCChannel; + +@protocol IRCConnectionDelegate +@optional +- (void)connection: (IRCConnection*)conn + didReceiveLine: (OFString*)line; +- (void)connection: (IRCConnection*)conn + didSendLine: (OFString*)line; +- (void)connectionWasEstablished: (IRCConnection*)conn; +- (void)connection: (IRCConnection*)conn + didSeeUser: (IRCUser*)user + joinChannel: (IRCChannel*)channel; +- (void)connection: (IRCConnection*)conn + didReceiveMessage: (OFString*)msg + fromUser: (IRCUser*)user + inChannel: (IRCChannel*)channel; +- (void)connection: (IRCConnection*)conn + didReceivePrivateMessage: (OFString*)msg + fromUser: (IRCUser*)user; +@end + +@interface IRCConnection: OFObject +{ + OFTCPSocket *sock; + OFString *server; + uint16_t port; + OFString *nickname, *username, *realname; + OFMutableDictionary *channels; + id delegate; +} + +@property (copy) OFString *server; +@property (assign) uint16_t port; +@property (copy) OFString *nickname, *username, *realname; +@property (retain) id delegate; + +- (void)connect; +- (void)disconnect; +- (void)disconnectWithReason: (OFString*)reason; +- (void)joinChannel: (OFString*)channelName; +- (void)leaveChannel: (IRCChannel*)channel; +- (void)leaveChannel: (IRCChannel*)channel + withReason: (OFString*)reason; +- (void)sendLine: (OFString*)line; +- (void)sendLineWithFormat: (OFString*)line, ...; +- (void)handleConnection; +@end diff --git a/src/IRCConnection.m b/src/IRCConnection.m new file mode 100644 index 0000000..69df2e6 --- /dev/null +++ b/src/IRCConnection.m @@ -0,0 +1,267 @@ +/* + * Copyright (c) 2010, 2011, Jonathan Schleifer + * + * https://webkeks.org/hg/objirc/ + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#import +#import +#import +#import +#import +#import +#import + +#import "IRCConnection.h" +#import "IRCUser.h" +#import "IRCChannel.h" + +@implementation IRCConnection +@synthesize server, port, nickname, username, realname, delegate; + +- init +{ + self = [super init]; + + @try { + channels = [[OFMutableDictionary alloc] init]; + port = 6667; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)connect +{ + OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; + + sock = [[OFTCPSocket alloc] init]; + [sock connectToHost: server + onPort: port]; + + [self sendLineWithFormat: @"NICK %@", nickname]; + [self sendLineWithFormat: @"USER %@ * 0 :%@", username, realname]; + + [pool release]; +} + +- (void)disconnect +{ + [self disconnectWithReason: nil]; +} + +- (void)disconnectWithReason: (OFString*)reason +{ + if (reason == nil) + [self sendLine: @"QUIT"]; + else + [self sendLineWithFormat: @"QUIT :%@", reason]; +} + +- (void)joinChannel: (OFString*)channelName +{ + [self sendLineWithFormat: @"JOIN %@", channelName]; +} + +- (void)leaveChannel: (IRCChannel*)channel +{ + [self leaveChannel: channel + withReason: nil]; +} + +- (void)leaveChannel: (IRCChannel*)channel + withReason: (OFString*)reason +{ + if (reason == nil) + [self sendLineWithFormat: @"PART %@", channel.name]; + else + [self sendLineWithFormat: @"PART %@ :%@", channel.name, reason]; + + [channels removeObjectForKey: channel.name]; +} + +- (void)sendLine: (OFString*)line +{ + if ([delegate respondsToSelector: @selector(connection:didSendLine:)]) + [delegate connection: self + didSendLine: line]; + + [sock writeLine: line]; +} + +- (void)sendLineWithFormat: (OFString*)format, ... +{ + OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; + OFString *line; + va_list args; + + va_start(args, format); + line = [[[OFString alloc] initWithFormat: format + arguments: args] autorelease]; + va_end(args); + + [self sendLine: line]; + + [pool release]; +} + +- (void)handleConnection +{ + OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; + OFString *line; + OFArray *splitted; + + for (;;) { + @try { + line = [sock readLine]; + } @catch (OFInvalidEncodingException *e) { + [e dealloc]; + line = [sock readLineWithEncoding: + OF_STRING_ENCODING_WINDOWS_1252]; + } + + if (line == nil) + break; + + if ([delegate respondsToSelector: + @selector(connection:didReceiveLine:)]) + [delegate connection: self + didReceiveLine: line]; + + splitted = [line componentsSeparatedByString: @" "]; + + /* PING */ + if (splitted.count == 2 && + [splitted.firstObject isEqual: @"PING"]) { + OFMutableString *s = [[line mutableCopy] autorelease]; + [s replaceOccurrencesOfString: @"PING" + withString: @"PONG"]; + [self sendLine: s]; + + continue; + } + + /* Connected */ + if (splitted.count >= 4 && + [[splitted objectAtIndex: 1] isEqual: @"001"]) { + if ([delegate respondsToSelector: + @selector(connectionWasEstablished:)]) + [delegate connectionWasEstablished: self]; + + continue; + } + + /* JOIN */ + if (splitted.count == 3 && + [[splitted objectAtIndex: 1] isEqual: @"JOIN"]) { + OFString *who = [splitted objectAtIndex: 0]; + OFString *where = [splitted objectAtIndex: 2]; + IRCUser *user; + IRCChannel *channel; + + who = [who substringFromIndex: 1 + toIndex: who.length]; + where = [where substringFromIndex: 1 + toIndex: where.length]; + + user = [IRCUser IRCUserWithString: who]; + + if ([who hasPrefix: + [nickname stringByAppendingString: @"!"]]) { + channel = [IRCChannel channelWithName: where]; + [channels setObject: channel + forKey: where]; + } else + channel = [channels objectForKey: where]; + + if ([delegate respondsToSelector: + @selector(connection:didSeeUser:joinChannel:)]) + [delegate connection: self + didSeeUser: user + joinChannel: channel]; + + continue; + } + + /* PRIVMSG */ + if (splitted.count >= 4 && + [[splitted objectAtIndex: 1] isEqual: @"PRIVMSG"]) { + OFString *from = [splitted objectAtIndex: 0]; + OFString *to = [splitted objectAtIndex: 2]; + IRCUser *user; + OFString *msg; + size_t pos = from.length + 1 + + [[splitted objectAtIndex: 1] length] + 1 + + to.length; + + from = [from substringFromIndex: 1 + toIndex: from.length]; + msg = [line substringFromIndex: pos + 2 + toIndex: line.length]; + + user = [IRCUser IRCUserWithString: from]; + + if (![to isEqual: nickname]) { + IRCChannel *channel; + + channel = [channels objectForKey: to]; + + if ([delegate respondsToSelector: + @selector(connection:didReceiveMessage: + fromUser:inChannel:)]) + [delegate connection: self + didReceiveMessage: msg + fromUser: user + inChannel: channel]; + } else { + if ([delegate respondsToSelector: + @selector(connection: + didReceivePrivateMessage:fromUser:)]) + [delegate + connection: self + didReceivePrivateMessage: msg + fromUser: user]; + } + + continue; + } + + [pool releaseObjects]; + } + + [pool release]; +} + +- (void)dealloc +{ + [sock release]; + [server release]; + [nickname release]; + [username release]; + [realname release]; + [channels release]; + + [super dealloc]; +} +@end diff --git a/src/IRCUser.h b/src/IRCUser.h new file mode 100644 index 0000000..9170146 --- /dev/null +++ b/src/IRCUser.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2010, 2011, Jonathan Schleifer + * + * https://webkeks.org/hg/objirc/ + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#import + +@interface IRCUser: OFObject +{ + OFString *nickname; + OFString *username; + OFString *hostname; +} + +@property (copy, readonly) OFString *nickname, *username, *hostname; + ++ IRCUserWithString: (OFString*)str; +- initWithString: (OFString*)str; +@end diff --git a/src/IRCUser.m b/src/IRCUser.m new file mode 100644 index 0000000..25cd17b --- /dev/null +++ b/src/IRCUser.m @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2010, 2011, Jonathan Schleifer + * + * https://webkeks.org/hg/objirc/ + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#import "IRCUser.h" + +@implementation IRCUser +@synthesize username, nickname, hostname; ++ IRCUserWithString: (OFString*)str +{ + return [[[self alloc] initWithString: str] autorelease]; +} + +- initWithString: (OFString*)str +{ + char *tmp2 = NULL; + + self = [super init]; + + @try { + char *tmp; + + if ((tmp2 = strdup(str.cString)) == NULL) + @throw [OFOutOfMemoryException + newWithClass: isa + requestedSize: str.cStringLength]; + + if ((tmp = strchr(tmp2, '@')) == NULL) + @throw [OFInvalidFormatException newWithClass: isa]; + + *tmp = '\0'; + hostname = [[OFString alloc] initWithCString: tmp + 1]; + + if ((tmp = strchr(tmp2, '!')) == NULL) + @throw [OFInvalidFormatException newWithClass: isa]; + + *tmp = '\0'; + username = [[OFString alloc] initWithCString: tmp + 1]; + + nickname = [[OFString alloc] initWithCString: tmp2]; + } @catch (id e) { + [self release]; + @throw e; + } @finally { + if (tmp2 != NULL) + free(tmp2); + } + + return self; +} + +- (void)dealloc +{ + [nickname release]; + [username release]; + [hostname release]; + + [super dealloc]; +} + +- copy +{ + return [self retain]; +} + +- (OFString*)description +{ + return [OFString stringWithFormat: @"%@!%@@%@", + nickname, username, hostname]; +} +@end diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 0000000..3c84679 --- /dev/null +++ b/src/Makefile @@ -0,0 +1,5 @@ +all: + objfw-compile -Wall -g --lib 0.0 -o objirc *.m + +clean: + rm -f *.o *.so *.dylib *.dll diff --git a/tests/Makefile b/tests/Makefile new file mode 100644 index 0000000..f1314b5 --- /dev/null +++ b/tests/Makefile @@ -0,0 +1,5 @@ +all: + objfw-compile -Wall -g -o tests *.m -I../src -L../src -lobjirc + +clean: + rm -f tests *.o diff --git a/tests/test.m b/tests/test.m new file mode 100644 index 0000000..6101963 --- /dev/null +++ b/tests/test.m @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2010, 2011, Jonathan Schleifer + * + * https://webkeks.org/hg/objirc/ + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#import + +#import "IRCConnection.h" +#import "IRCUser.h" +#import "IRCChannel.h" + +@interface TestApp: OFObject +@end + +OF_APPLICATION_DELEGATE(TestApp) + +@implementation TestApp +- (void)applicationDidFinishLaunching +{ + IRCConnection *conn = [[IRCConnection alloc] init]; + + conn.server = @"leguin.freenode.net"; + conn.nickname = @"ObjIRC"; + conn.username = @"ObjIRC"; + conn.realname = @"ObjIRC"; + conn.delegate = self; + + [conn connect]; + [conn handleConnection]; +} + +- (void)connection: (IRCConnection*)conn + didReceiveLine: (OFString*)line +{ + [of_stderr writeFormat: @"> %@\n", line]; +} + +- (void)connection: (IRCConnection*)conn + didSendLine: (OFString*)line +{ + [of_stderr writeFormat: @"< %@\n", line]; +} + +- (void)connectionWasEstablished: (IRCConnection*)conn +{ + [conn joinChannel: @"#objfw"]; +} + +- (void)connection: (IRCConnection*)conn + didSeeUser: (IRCUser*)user + joinChannel: (IRCChannel*)channel +{ + of_log(@"%@ joined %@.", user, channel.name); +} + +- (void)connection: (IRCConnection*)conn + didReceiveMessage: (OFString*)msg + fromUser: (IRCUser*)user + inChannel: (IRCChannel*)channel +{ + of_log(@"[%@] %@: %@", channel.name, user, msg); +} + +- (void)connection: (IRCConnection*)conn + didReceivePrivateMessage: (OFString*)msg + fromUser: (IRCUser*)user +{ + of_log(@"(%@): %@", user, msg); +} +@end