diff --git a/IRCClient.xcodeproj/project.pbxproj b/IRCClient.xcodeproj/project.pbxproj index 6dee4e3..6a9206b 100644 --- a/IRCClient.xcodeproj/project.pbxproj +++ b/IRCClient.xcodeproj/project.pbxproj @@ -10,16 +10,8 @@ 8657E6E21C2B55B900BD4E50 /* IRC_Numerics.plist in Resources */ = {isa = PBXBuildFile; fileRef = 8657E6E11C2B55B900BD4E50 /* IRC_Numerics.plist */; }; 86627E21276648E400AEFEB7 /* NSData+SA_NSDataExtensions.h in Headers */ = {isa = PBXBuildFile; fileRef = 86627E1F276648E400AEFEB7 /* NSData+SA_NSDataExtensions.h */; }; 86627E22276648E400AEFEB7 /* NSData+SA_NSDataExtensions.m in Sources */ = {isa = PBXBuildFile; fileRef = 86627E20276648E400AEFEB7 /* NSData+SA_NSDataExtensions.m */; }; - 86769D6D1C94DC5300B86A72 /* config.h in Headers */ = {isa = PBXBuildFile; fileRef = 86769D5B1C94DC5300B86A72 /* config.h */; }; - 86769D6E1C94DC5300B86A72 /* dcc.h in Headers */ = {isa = PBXBuildFile; fileRef = 86769D5C1C94DC5300B86A72 /* dcc.h */; }; - 86769D6F1C94DC5300B86A72 /* libirc_errors.h in Headers */ = {isa = PBXBuildFile; fileRef = 86769D5D1C94DC5300B86A72 /* libirc_errors.h */; }; - 86769D701C94DC5300B86A72 /* libirc_events.h in Headers */ = {isa = PBXBuildFile; fileRef = 86769D5E1C94DC5300B86A72 /* libirc_events.h */; }; - 86769D711C94DC5300B86A72 /* libirc_options.h in Headers */ = {isa = PBXBuildFile; fileRef = 86769D5F1C94DC5300B86A72 /* libirc_options.h */; }; - 86769D721C94DC5300B86A72 /* libirc_rfcnumeric.h in Headers */ = {isa = PBXBuildFile; fileRef = 86769D601C94DC5300B86A72 /* libirc_rfcnumeric.h */; }; - 86769D731C94DC5300B86A72 /* libircclient.h in Headers */ = {isa = PBXBuildFile; fileRef = 86769D611C94DC5300B86A72 /* libircclient.h */; }; - 86769D741C94DC5300B86A72 /* params.h in Headers */ = {isa = PBXBuildFile; fileRef = 86769D621C94DC5300B86A72 /* params.h */; }; - 86769D751C94DC5300B86A72 /* session.h in Headers */ = {isa = PBXBuildFile; fileRef = 86769D631C94DC5300B86A72 /* session.h */; }; - 86769D791C94DC5300B86A72 /* libircclient.c in Sources */ = {isa = PBXBuildFile; fileRef = 86769D681C94DC5300B86A72 /* libircclient.c */; }; + 86715FFA276F609300024F7C /* NSStream+QNetworkAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 86715FF8276F609300024F7C /* NSStream+QNetworkAdditions.h */; }; + 86715FFB276F609300024F7C /* NSStream+QNetworkAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 86715FF9276F609300024F7C /* NSStream+QNetworkAdditions.m */; }; 868374A91C24E774005B97E5 /* IRCClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 868374A81C24E774005B97E5 /* IRCClient.h */; settings = {ATTRIBUTES = (Public, ); }; }; 86B0D3E922C5A3D700E60877 /* NSRange-Conventional.h in Headers */ = {isa = PBXBuildFile; fileRef = 86B0D3E822C5A3D700E60877 /* NSRange-Conventional.h */; }; 86B0D3EC22C5FF1300E60877 /* NSArray+SA_NSArrayExtensions.h in Headers */ = {isa = PBXBuildFile; fileRef = 86B0D3EA22C5FF1300E60877 /* NSArray+SA_NSArrayExtensions.h */; }; @@ -41,16 +33,8 @@ 8657E6E11C2B55B900BD4E50 /* IRC_Numerics.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = IRC_Numerics.plist; sourceTree = ""; }; 86627E1F276648E400AEFEB7 /* NSData+SA_NSDataExtensions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSData+SA_NSDataExtensions.h"; path = "../../SA_NSDataExtensions/NSData+SA_NSDataExtensions.h"; sourceTree = ""; }; 86627E20276648E400AEFEB7 /* NSData+SA_NSDataExtensions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSData+SA_NSDataExtensions.m"; path = "../../SA_NSDataExtensions/NSData+SA_NSDataExtensions.m"; sourceTree = ""; }; - 86769D5B1C94DC5300B86A72 /* config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = config.h; sourceTree = ""; }; - 86769D5C1C94DC5300B86A72 /* dcc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dcc.h; sourceTree = ""; }; - 86769D5D1C94DC5300B86A72 /* libirc_errors.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = libirc_errors.h; sourceTree = ""; }; - 86769D5E1C94DC5300B86A72 /* libirc_events.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = libirc_events.h; sourceTree = ""; }; - 86769D5F1C94DC5300B86A72 /* libirc_options.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = libirc_options.h; sourceTree = ""; }; - 86769D601C94DC5300B86A72 /* libirc_rfcnumeric.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = libirc_rfcnumeric.h; sourceTree = ""; }; - 86769D611C94DC5300B86A72 /* libircclient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = libircclient.h; sourceTree = ""; }; - 86769D621C94DC5300B86A72 /* params.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = params.h; sourceTree = ""; }; - 86769D631C94DC5300B86A72 /* session.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = session.h; sourceTree = ""; }; - 86769D681C94DC5300B86A72 /* libircclient.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = libircclient.c; sourceTree = ""; }; + 86715FF8276F609300024F7C /* NSStream+QNetworkAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSStream+QNetworkAdditions.h"; path = "../NSStream+QNetworkAddtions/NSStream+QNetworkAdditions.h"; sourceTree = ""; }; + 86715FF9276F609300024F7C /* NSStream+QNetworkAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSStream+QNetworkAdditions.m"; path = "../NSStream+QNetworkAddtions/NSStream+QNetworkAdditions.m"; sourceTree = ""; }; 868374A81C24E774005B97E5 /* IRCClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IRCClient.h; sourceTree = ""; }; 86B0D3E822C5A3D700E60877 /* NSRange-Conventional.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSRange-Conventional.h"; path = "../NSRange-Conventional.h"; sourceTree = ""; }; 86B0D3EA22C5FF1300E60877 /* NSArray+SA_NSArrayExtensions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; name = "NSArray+SA_NSArrayExtensions.h"; path = "../../OS X Projects/SA_IRCBotServer/NSArray+SA_NSArrayExtensions/NSArray+SA_NSArrayExtensions.h"; sourceTree = ""; }; @@ -91,37 +75,13 @@ path = SA_NSDataExtensions; sourceTree = ""; }; - 86769D591C94DC5300B86A72 /* libircclient */ = { + 86715FF7276F608200024F7C /* NSStream+QNetworkAdditions */ = { isa = PBXGroup; children = ( - 86769D5A1C94DC5300B86A72 /* include */, - 86769D641C94DC5300B86A72 /* src */, + 86715FF8276F609300024F7C /* NSStream+QNetworkAdditions.h */, + 86715FF9276F609300024F7C /* NSStream+QNetworkAdditions.m */, ); - path = libircclient; - sourceTree = ""; - }; - 86769D5A1C94DC5300B86A72 /* include */ = { - isa = PBXGroup; - children = ( - 86769D5B1C94DC5300B86A72 /* config.h */, - 86769D5C1C94DC5300B86A72 /* dcc.h */, - 86769D5D1C94DC5300B86A72 /* libirc_errors.h */, - 86769D5E1C94DC5300B86A72 /* libirc_events.h */, - 86769D5F1C94DC5300B86A72 /* libirc_options.h */, - 86769D601C94DC5300B86A72 /* libirc_rfcnumeric.h */, - 86769D611C94DC5300B86A72 /* libircclient.h */, - 86769D621C94DC5300B86A72 /* params.h */, - 86769D631C94DC5300B86A72 /* session.h */, - ); - path = include; - sourceTree = ""; - }; - 86769D641C94DC5300B86A72 /* src */ = { - isa = PBXGroup; - children = ( - 86769D681C94DC5300B86A72 /* libircclient.c */, - ); - path = src; + name = "NSStream+QNetworkAdditions"; sourceTree = ""; }; 86B0D3E722C5A3B400E60877 /* NSString+SA_NSStringExtensions */ = { @@ -154,13 +114,13 @@ 86F2EFDC1C21F73600B033A4 = { isa = PBXGroup; children = ( + 86715FF7276F608200024F7C /* NSStream+QNetworkAdditions */, 86BAE5A3232ABFD600936147 /* NSIndexSet+SA_NSIndexSetExtensions */, 86B0D3E822C5A3D700E60877 /* NSRange-Conventional.h */, 86B0D3EE22C5FF1700E60877 /* NSArray+SA_NSArrayExtensions */, 86B0D3E722C5A3B400E60877 /* NSString+SA_NSStringExtensions */, 866B9D4F1C97530E00F460BB /* NSData+SA_NSDataExtensions */, 868374A81C24E774005B97E5 /* IRCClient.h */, - 86769D591C94DC5300B86A72 /* libircclient */, 86F2EFE81C21F73600B033A4 /* IRCClient */, 86F2EFE71C21F73600B033A4 /* Products */, ); @@ -200,22 +160,14 @@ 868374A91C24E774005B97E5 /* IRCClient.h in Headers */, 86F2EFFE1C21F81900B033A4 /* IRCClientSessionDelegate.h in Headers */, 86F2EFF91C21F81900B033A4 /* IRCClientChannel.h in Headers */, - 86769D751C94DC5300B86A72 /* session.h in Headers */, - 86769D6E1C94DC5300B86A72 /* dcc.h in Headers */, 86B0D3E922C5A3D700E60877 /* NSRange-Conventional.h in Headers */, 86627E21276648E400AEFEB7 /* NSData+SA_NSDataExtensions.h in Headers */, 86F2EFFB1C21F81900B033A4 /* IRCClientChannelDelegate.h in Headers */, - 86769D721C94DC5300B86A72 /* libirc_rfcnumeric.h in Headers */, 86D02CE0275B9E6B00876E93 /* NSString+SA_NSStringExtensions.h in Headers */, - 86769D6D1C94DC5300B86A72 /* config.h in Headers */, - 86769D731C94DC5300B86A72 /* libircclient.h in Headers */, - 86769D741C94DC5300B86A72 /* params.h in Headers */, + 86715FFA276F609300024F7C /* NSStream+QNetworkAdditions.h in Headers */, 86F2EFFC1C21F81900B033A4 /* IRCClientSession.h in Headers */, - 86769D701C94DC5300B86A72 /* libirc_events.h in Headers */, 86BAE5A2232ABFD200936147 /* NSIndexSet+SA_NSIndexSetExtensions.h in Headers */, 86B0D3EC22C5FF1300E60877 /* NSArray+SA_NSArrayExtensions.h in Headers */, - 86769D6F1C94DC5300B86A72 /* libirc_errors.h in Headers */, - 86769D711C94DC5300B86A72 /* libirc_options.h in Headers */, 86F2EFF81C21F81900B033A4 /* IRCClientChannel_Private.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; @@ -289,12 +241,12 @@ buildActionMask = 2147483647; files = ( 86BAE5A1232ABFD200936147 /* NSIndexSet+SA_NSIndexSetExtensions.m in Sources */, + 86715FFB276F609300024F7C /* NSStream+QNetworkAdditions.m in Sources */, 86F2EFFD1C21F81900B033A4 /* IRCClientSession.m in Sources */, 86B0D3ED22C5FF1300E60877 /* NSArray+SA_NSArrayExtensions.m in Sources */, 86D02CE1275B9E6B00876E93 /* NSString+SA_NSStringExtensions.m in Sources */, 86F2EFFA1C21F81900B033A4 /* IRCClientChannel.m in Sources */, 86627E22276648E400AEFEB7 /* NSData+SA_NSDataExtensions.m in Sources */, - 86769D791C94DC5300B86A72 /* libircclient.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -437,11 +389,9 @@ GCC_WARN_SHADOW = YES; GCC_WARN_SIGN_COMPARE = YES; GCC_WARN_UNUSED_LABEL = YES; - HEADER_SEARCH_PATHS = ""; INFOPLIST_FILE = IRCClient/Info.plist; INSTALL_PATH = "@executable_path/../Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; - LIBRARY_SEARCH_PATHS = "$(PROJECT_DIR)/libircclient"; MACOSX_DEPLOYMENT_TARGET = 10.6; ONLY_ACTIVE_ARCH = NO; PRODUCT_BUNDLE_IDENTIFIER = saidachmiz.IRCClient; @@ -471,11 +421,9 @@ GCC_WARN_SHADOW = YES; GCC_WARN_SIGN_COMPARE = YES; GCC_WARN_UNUSED_LABEL = YES; - HEADER_SEARCH_PATHS = ""; INFOPLIST_FILE = IRCClient/Info.plist; INSTALL_PATH = "@executable_path/../Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; - LIBRARY_SEARCH_PATHS = "$(PROJECT_DIR)/libircclient"; MACOSX_DEPLOYMENT_TARGET = 10.6; ONLY_ACTIVE_ARCH = NO; PRODUCT_BUNDLE_IDENTIFIER = saidachmiz.IRCClient; diff --git a/IRCClient/IRCClientChannel.h b/IRCClient/IRCClientChannel.h index 156302d..ce03531 100644 --- a/IRCClient/IRCClientChannel.h +++ b/IRCClient/IRCClientChannel.h @@ -88,7 +88,7 @@ * * @param aTopic The topic the client wishes to set for the channel. */ --(int) setChannelTopic:(NSData *)newTopic; +-(int) channelTopic:(NSData *)newTopic; /** Sets the mode of the channel. * @@ -98,8 +98,8 @@ * * @param mode The mode to set the channel to. */ --(int) setMode:(NSData *)mode - params:(NSData *)params; +-(int) channelMode:(NSData *)mode + params:(NSData *)params; /** Sends a public PRIVMSG to the channel. If you try to send more than can fit on an IRC buffer, it will be truncated. diff --git a/IRCClient/IRCClientChannel.m b/IRCClient/IRCClientChannel.m index bf60a6b..4787cb3 100644 --- a/IRCClient/IRCClientChannel.m +++ b/IRCClient/IRCClientChannel.m @@ -16,8 +16,6 @@ /********************************************/ @interface IRCClientChannel() { - irc_session_t *_irc_session; - // TODO: actually keep track of nicks! Use RPL_NAMREPLY and so on... // (see refreshNames...) NSMutableArray *_nicks; @@ -39,10 +37,6 @@ return [_nicks copy]; } --(IRCClientSession *) session { - return (__bridge IRCClientSession *) irc_get_ctx(_irc_session); -} - /********************************************/ #pragma mark - Initializers & factory methods /********************************************/ @@ -56,11 +50,11 @@ /**************************/ -(instancetype) initWithName:(NSData *)name - andIRCSession:(irc_session_t *)irc_session { + andIRCSession:(IRCClientSession *)session { if (!(self = [super init])) return nil; - _irc_session = irc_session; + _session = session; _name = name; _encoding = NSUTF8StringEncoding; @@ -76,119 +70,102 @@ /**************************/ -(int) part { - return irc_send_raw(_irc_session, - "PART %s", - _name.terminatedCString); + [_session sendRaw:[NSData dataWithFormat:"PART %@", _name, nil]]; + + return 0; } -(int) invite:(NSData *)nick { if (!nick || nick.length == 0) - return LIBIRC_ERR_STATE; + return 1; +// return LIBIRC_ERR_STATE; - return irc_send_raw(_irc_session, - "INVITE %s %s", - nick.terminatedCString, - _name.terminatedCString); + [_session sendRaw:[NSData dataWithFormat:"INVITE %@ %@", nick, _name, nil]]; + + return 0; } -(int) refreshNames { - return irc_send_raw(_irc_session, - "NAMES %s", - _name.terminatedCString); + [_session sendRaw:[NSData dataWithFormat:"NAMES %@", _name, nil]]; + + return 0; } --(int) setChannelTopic:(NSData *)newTopic { +-(int) channelTopic:(NSData *)newTopic { if (newTopic) - return irc_send_raw(_irc_session, - "TOPIC %s :%s", - _name.terminatedCString, - newTopic.terminatedCString); + [_session sendRaw:[NSData dataWithFormat:"TOPIC %@ :%@", _name, newTopic, nil]]; else - return irc_send_raw(_irc_session, - "TOPIC %s", - _name.terminatedCString); + [_session sendRaw:[NSData dataWithFormat:"TOPIC %@", _name, nil]]; + + return 0; } --(int) setMode:(NSData *)mode - params:(NSData *)params { +-(int) channelMode:(NSData *)mode + params:(NSData *)params { if (mode != nil) { - NSMutableData *fullModeString = ((params != nil) ? - [NSMutableData dataWithLength:mode.length + 1 + params.length] : - [NSMutableData dataWithLength:mode.length + 1]); - sprintf(fullModeString.mutableBytes, - "%s %s", - mode.terminatedCString, - params.terminatedCString); - - return irc_send_raw(_irc_session, - "MODE %s %s", - _name.terminatedCString, - fullModeString.terminatedCString); + if (params != nil) + [_session sendRaw:[NSData dataWithFormat:"MODE %@ %@ %@", _name, mode, params, nil]]; + else + [_session sendRaw:[NSData dataWithFormat:"MODE %@ %@", _name, mode, nil]]; } else { - return irc_send_raw(_irc_session, - "MODE %s", - _name.terminatedCString); + [_session sendRaw:[NSData dataWithFormat:"MODE %@", _name, nil]]; } + + return 0; } -(int) message:(NSData *)message { if (!message || message.length == 0) - return LIBIRC_ERR_STATE; + return 1; +// return LIBIRC_ERR_STATE; - return irc_send_raw(_irc_session, - "PRIVMSG %s :%s", - _name.terminatedCString, -// irc_color_convert_to_mirc(message.terminatedCString)); - [self.session colorConvertToMIRC:message].terminatedCString); + [_session sendRaw:[NSData dataWithFormat:"PRIVMSG %@ :%@", _name, [self.session colorConvertToMIRC:message], nil]]; + + return 0; } -(int) action:(NSData *)action { if (!action || action.length == 0) - return LIBIRC_ERR_STATE; + return 1; +// return LIBIRC_ERR_STATE; - return irc_send_raw(_irc_session, - "PRIVMSG %s :\x01" "ACTION %s\x01", - _name.terminatedCString, -// irc_color_convert_to_mirc(action.terminatedCString)); - [self.session colorConvertToMIRC:action].terminatedCString); + [_session sendRaw:[NSData dataWithFormat:"PRIVMSG %@ :\x01" "ACTION %@\x01", _name, [self.session colorConvertToMIRC:action], nil]]; + + return 0; } -(int) notice:(NSData *)notice { if (!notice || notice.length == 0) - return LIBIRC_ERR_STATE; + return 1; +// return LIBIRC_ERR_STATE; - return irc_send_raw(_irc_session, - "NOTICE %s :%s", - _name.terminatedCString, - notice.terminatedCString); + [_session sendRaw:[NSData dataWithFormat:"NOTICE %@ :%@", _name, notice, nil]]; + + return 0; } -(int) kick:(NSData *)nick reason:(NSData *)reason { if (!nick || nick.length == 0) - return LIBIRC_ERR_STATE; + return 1; +// return LIBIRC_ERR_STATE; if (reason) - return irc_send_raw(_irc_session, - "KICK %s %s :%s", - _name.terminatedCString, - nick.terminatedCString, - reason.terminatedCString); + [_session sendRaw:[NSData dataWithFormat:"KICK %@ %@ :%@", _name, nick, reason, nil]]; else - return irc_send_raw(_irc_session, - "KICK %s %s", - _name.terminatedCString, - nick.terminatedCString); + [_session sendRaw:[NSData dataWithFormat:"KICK %@ %@", _name, nick, nil]]; + + return 0; } -(int) ctcpRequest:(NSData *)request { if (!request || request.length == 0) - return LIBIRC_ERR_STATE; + return 1; +// return LIBIRC_ERR_STATE; - return irc_send_raw(_irc_session, - "PRIVMSG %s :\x01%s\x01", - _name.terminatedCString, - request.terminatedCString); + [_session sendRaw:[NSData dataWithFormat:"PRIVMSG %@ :\x01%@\x01", _name, request, nil]]; + + return 0; } /****************************/ diff --git a/IRCClient/IRCClientChannel_Private.h b/IRCClient/IRCClientChannel_Private.h index 1cf9dd3..4bdcabe 100644 --- a/IRCClient/IRCClientChannel_Private.h +++ b/IRCClient/IRCClientChannel_Private.h @@ -9,7 +9,6 @@ #import "IRCClientChannel.h" #import "IRCClientSession.h" -#include "libircclient.h" /********************************************/ #pragma mark IRCClientChannel class extension @@ -20,14 +19,14 @@ /** initWithName:andIRCSession: * * Returns an initialised IRCClientChannel with a given channel name, associated - * with the given irc_session_t object. You are not expected to initialize your + * with the given IRCClientSession object. You are not expected to initialize your * own IRCClientChannel objects; if you wish to join a channel you should send a * [IRCClientSession join:key:] message to your IRCClientSession object. * * @param aName Name of the channel. */ -(instancetype) initWithName:(NSData *)aName - andIRCSession:(irc_session_t *)session; + andIRCSession:(IRCClientSession *)session; /****************************/ #pragma mark - Event handlers diff --git a/IRCClient/IRCClientSession.h b/IRCClient/IRCClientSession.h index 235512f..8911d8e 100644 --- a/IRCClient/IRCClientSession.h +++ b/IRCClient/IRCClientSession.h @@ -27,7 +27,7 @@ #pragma mark IRCClientSession class declaration /**********************************************/ -@interface IRCClientSession : NSObject +@interface IRCClientSession : NSObject /******************************/ #pragma mark - Class properties @@ -85,22 +85,21 @@ /** The suggested text encoding for messages on this server. This is almost entirely irrelevant (except for CTCP TIME replies), as - all messages and other strings are taken and returned as C strings - encapsulated in NSData objects. This property is for your convenience. + all messages and other strings are taken and returned as NSData objects. + This property is for your convenience. You may change this at any time. */ @property (assign) NSStringEncoding encoding; /** An NSDictionary of channels that the client is currently connected to. - Keys are channel names (NSData objects containing C strings), values are - IRCClientChannel objects. + Keys are channel names (NSData), values are IRCClientChannel objects. */ @property (nonatomic, readonly) NSDictionary *channels; /** Returns YES if the server is currently connected successfully, and NO if it is not. */ -@property (readonly, getter=isConnected) bool connected; +@property (readonly, getter=isConnected) BOOL connected; /** Stores arbitrary user info. */ @property (nonatomic, readonly) NSMutableDictionary *userInfo; @@ -137,20 +136,20 @@ /** Set the nickname, username, and realname for the session. - Returns 1 if successfully set, 0 otherwise. - (0 is returned if you try to call this method after the session has + Returns YES if successfully set, NO otherwise. + (NO is returned if you try to call this method after the session has already connected; use the nick: method to attempt a nick change while connected.) */ --(int) setNickname:(NSData *)nickname - username:(NSData *)username - realname:(NSData *)realname; +-(BOOL) setNickname:(NSData *)nickname + username:(NSData *)username + realname:(NSData *)realname; /** Connect to the IRC server. Note that this performs the initial DNS lookup and the TCP connection, so if there are any problems you will be notified via the return code of the message. - + Look at the libircclient documentation for the different return codes. */ -(int) connect; @@ -162,12 +161,6 @@ */ -(void) disconnect; -/** Starts a new thread and starts the libircclient runloop, processing events and - firing messages back to the main runloop as required. Calling this again will - do nothing other than raise a warning in your logs. - */ --(void) run; - /** Convert libircclient markup in a message to mIRC format codes. */ -(NSData *) colorConvertToMIRC:(NSData *)message; diff --git a/IRCClient/IRCClientSession.m b/IRCClient/IRCClientSession.m index fca68e6..2d3a415 100644 --- a/IRCClient/IRCClientSession.m +++ b/IRCClient/IRCClientSession.m @@ -11,7 +11,7 @@ #pragma mark Defines and includes /********************************/ -#define IRCCLIENTVERSION "2.0a5" +#define IRCCLIENTVERSION "2.1a1" #import "IRCClientSession.h" #import "IRCClientChannel.h" @@ -22,27 +22,44 @@ #import "NSString+SA_NSStringExtensions.h" #import "NSRange-Conventional.h" #import "NSIndexSet+SA_NSIndexSetExtensions.h" +#import "NSStream+QNetworkAdditions.h" -/********************************************/ -#pragma mark - Callback function declarations -/********************************************/ +/******************************/ +#pragma mark - Static variables +/******************************/ -static void onEvent (irc_session_t *session, const char *event, const char *origin, const char **params, unsigned int count); -static void onNumericEvent (irc_session_t *session, unsigned int event, const char *origin, const char **params, unsigned int count); -static void onDCCChatRequest(irc_session_t *session, const char *nick, const char *addr, irc_dcc_t dccid); -static void onDCCSendRequest(irc_session_t *session, const char *nick, const char *addr, const char *filename, size_t size, irc_dcc_t dccid); +static const char *C_string_crlf = "\r\n"; static NSDictionary* ircNumericCodeList; +/******************************/ +#pragma mark - Type definitions +/******************************/ + +// TODO: more states? maybe to do with the NSStreamDelegate options? +typedef NS_OPTIONS(NSUInteger, IRCClientSessionStateFlags) { + IRCClientSessionConnected = 1 << 0, + IRCClientSessionMOTDReceived = 1 << 1 +}; + /***************************************************/ #pragma mark - IRCClientSession class implementation /***************************************************/ @implementation IRCClientSession { - irc_callbacks_t _callbacks; - irc_session_t *_irc_session; + NSInputStream *_iStream; + NSOutputStream *_oStream; + + NSMutableData *_receivedData; + NSMutableData *_dataToSend; + + dispatch_queue_t _q; + + void (^_cleanupHandler)(); NSMutableDictionary *_channels; + + IRCClientSessionStateFlags _stateFlags; } /******************************/ @@ -53,8 +70,8 @@ static NSDictionary* ircNumericCodeList; return [_channels copy]; } --(bool) isConnected { - return irc_is_connected(_irc_session); +-(BOOL) isConnected { + return (_stateFlags & IRCClientSessionConnected); } +(NSDictionary *) ircNumericCodes { @@ -76,69 +93,22 @@ static NSDictionary* ircNumericCodeList; if (!(self = [super init])) return nil; - _callbacks.event_connect = onEvent; - _callbacks.event_ping = onEvent; - _callbacks.event_nick = onEvent; - _callbacks.event_quit = onEvent; - _callbacks.event_join = onEvent; - _callbacks.event_part = onEvent; - _callbacks.event_mode = onEvent; - _callbacks.event_umode = onEvent; - _callbacks.event_topic = onEvent; - _callbacks.event_kick = onEvent; - _callbacks.event_error = onEvent; - _callbacks.event_channel = onEvent; - _callbacks.event_privmsg = onEvent; - _callbacks.event_server_msg = onEvent; - _callbacks.event_notice = onEvent; - _callbacks.event_channel_notice = onEvent; - _callbacks.event_server_notice = onEvent; - _callbacks.event_invite = onEvent; - _callbacks.event_ctcp_req = onEvent; - _callbacks.event_ctcp_rep = onEvent; - _callbacks.event_ctcp_action = onEvent; - _callbacks.event_unknown = onEvent; - _callbacks.event_numeric = onNumericEvent; - _callbacks.event_dcc_chat_req = onDCCChatRequest; - _callbacks.event_dcc_send_req = onDCCSendRequest; - - _irc_session = irc_create_session(&_callbacks); - - if (!_irc_session) { - NSLog(@"Could not create irc_session."); - return nil; - } - - // Strip server info from nicks. - // irc_option_set(_irc_session, LIBIRC_OPTION_STRIPNICKS); - - // Set debug mode. - // irc_option_set(_irc_session, LIBIRC_OPTION_DEBUG); - - irc_set_ctx(_irc_session, (__bridge void *)(self)); - - unsigned int high, low; - irc_get_version (&high, &low); - - _version = [[NSString stringWithFormat:@"IRCClient Framework v%s (Said Achmiz) - libirc v%d.%d (Georgy Yunaev)", - IRCCLIENTVERSION, - high, - low] dataAsUTF8]; + _version = [[NSString stringWithFormat:@"IRCClient Framework v%s (Said Achmiz)", IRCCLIENTVERSION] dataAsUTF8]; _channels = [NSMutableDictionary dictionary]; _encoding = NSUTF8StringEncoding; _userInfo = [NSMutableDictionary dictionary]; + _q = dispatch_queue_create("Q", DISPATCH_QUEUE_SERIAL); + return self; } -(void) dealloc { - if (irc_is_connected(_irc_session)) { - NSLog(@"Warning: IRC Session is not disconnected on dealloc"); + if (self.isConnected) { + NSLog(@"WARNING: IRC Session is not disconnected on dealloc"); } - - irc_destroy_session(_irc_session); } /***************************/ @@ -149,46 +119,51 @@ static NSDictionary* ircNumericCodeList; if (nickUserHost == nil) return nil; - NSRange rangeOfNickUserSeparator = [nickUserHost rangeOfData:[NSData dataFromCString:"!"] - options:(NSDataSearchOptions) 0 - range:NSRangeMake(0, nickUserHost.length)]; + NSRange rangeOfNickUserSeparator = [nickUserHost rangeOfBytes:"!" + options:(NSDataSearchOptions) 0 + range:nickUserHost.fullRange]; - return (rangeOfNickUserSeparator.location == NSNotFound - ? nickUserHost - : [nickUserHost subdataWithRange:NSRangeMake(0, rangeOfNickUserSeparator.location)]); + if (rangeOfNickUserSeparator.location == NSNotFound) { + return nil; + } else { + NSRange rangeOfNick = NSRangeMake(0, rangeOfNickUserSeparator.location); + return [nickUserHost subdataWithRange:rangeOfNick]; + } } +(NSData *) userFromNickUserHost:(NSData *)nickUserHost { if (nickUserHost == nil) return nil; - NSRange rangeOfNickUserSeparator = [nickUserHost rangeOfData:[NSData dataFromCString:"!"] - options:(NSDataSearchOptions) 0 - range:NSRangeMake(0, nickUserHost.length)]; + NSRange rangeOfNickUserSeparator = [nickUserHost rangeOfBytes:"!" + options:(NSDataSearchOptions) 0 + range:nickUserHost.fullRange]; + NSRange rangeOfUserHostSeparator = [nickUserHost rangeOfBytes:"@" + options:(NSDataSearchOptions) 0 + range:nickUserHost.fullRange]; - NSRange rangeOfUserHostSeparator = [nickUserHost rangeOfData:[NSData dataFromCString:"@"] - options:(NSDataSearchOptions) 0 - range:NSRangeMake(0, nickUserHost.length)]; - - return (( rangeOfNickUserSeparator.location == NSNotFound - || rangeOfUserHostSeparator.location == NSNotFound) - ? [NSData data] - : [nickUserHost subdataWithRange:NSRangeMake(rangeOfNickUserSeparator.location + 1, - rangeOfUserHostSeparator.location - (rangeOfNickUserSeparator.location + 1))]); + if ( rangeOfNickUserSeparator.location == NSNotFound + || rangeOfUserHostSeparator.location == NSNotFound) { + return nil; + } else { + return [nickUserHost subdataWithRange:NSRangeMake(NSRangeMax(rangeOfNickUserSeparator), + rangeOfUserHostSeparator.location - NSRangeMax(rangeOfNickUserSeparator))]; + } } +(NSData *) hostFromNickUserHost:(NSData *)nickUserHost { if (nickUserHost == nil) return nil; - NSRange rangeOfUserHostSeparator = [nickUserHost rangeOfData:[NSData dataFromCString:"@"] - options:(NSDataSearchOptions) 0 - range:NSRangeMake(0, nickUserHost.length)]; + NSRange rangeOfUserHostSeparator = [nickUserHost rangeOfBytes:"@" + options:(NSDataSearchOptions) 0 + range:nickUserHost.fullRange]; - return (rangeOfUserHostSeparator.location == NSNotFound - ? [NSData data] - : [nickUserHost subdataWithRange:NSRangeMake(rangeOfUserHostSeparator.location + 1, - nickUserHost.length - (rangeOfUserHostSeparator.location + 1))]); + if (rangeOfUserHostSeparator.location == NSNotFound) { + return nil; + } else { + return [nickUserHost subdataWithRange:[nickUserHost rangeAfterRange:rangeOfUserHostSeparator]]; + } } // TODO: implement color support @@ -273,44 +248,393 @@ static NSDictionary* ircNumericCodeList; } } +/******************************/ +#pragma mark - NSStreamDelegate +/******************************/ + +-(void) stream:(NSStream *)stream + handleEvent:(NSStreamEvent)eventCode { + switch (eventCode) { + case NSStreamEventNone: { + NSLog(@"NSStreamEventNone"); + + break; + } + case NSStreamEventOpenCompleted: { + NSLog(@"NSStreamEventOpenCompleted"); + dispatch_async(_q, ^{ + _stateFlags |= IRCClientSessionConnected; + }); + + break; + } + case NSStreamEventHasBytesAvailable: { + NSLog(@"NSStreamEventHasBytesAvailable"); + dispatch_async(_q, ^{ + [self receiveData:((NSInputStream *) stream)]; + }); + + break; + } + case NSStreamEventHasSpaceAvailable: { + NSLog(@"NSStreamEventHasSpaceAvailable"); + dispatch_async(_q, ^{ + if (_dataToSend.length > 0) + [self sendData:((NSOutputStream *) stream)]; + }); + + break; + } + case NSStreamEventErrorOccurred: { + NSLog(@"NSStreamEventErrorOccurred"); + NSLog(@"%@", stream.streamError); + dispatch_async(_q, ^{ + [self disconnect]; + }); + + break; + } + case NSStreamEventEndEncountered: { + NSLog(@"NSStreamEventEndEncountered"); + dispatch_async(_q, ^{ + [self disconnect]; + }); + + break; + } + } +} + +/****************************/ +#pragma mark - Helper methods +/****************************/ + +-(void) sendData:(NSOutputStream *)stream { + if (self.isConnected == NO) + return; + + // Copy up to 512 bytes of data into a buffer. + NSUInteger bufferSize = (_dataToSend.length < 512 + ? _dataToSend.length + : 512); + uint8_t buffer[bufferSize]; + [_dataToSend getBytes:buffer + length:bufferSize]; + + // Write the buffer to the stream. + NSInteger bytesWritten = [stream write:buffer + maxLength:bufferSize]; + + if (bytesWritten < 0) { + NSLog(@"%@", stream.streamError); + [self disconnect]; + } else { + // Discard the sent bytes. + [_dataToSend replaceBytesInRange:NSRangeMake(0, ((NSUInteger) bytesWritten)) + withBytes:NULL + length:0]; + } +} + +-(void) receiveData:(NSInputStream *)stream { + if (self.isConnected == NO) + return; + + // Get some bytes from the stream. + NSUInteger bufferSize = 512; + uint8_t buffer[bufferSize]; + NSInteger bytesRead = [stream read:buffer + maxLength:bufferSize]; + + if (bytesRead < 0) { + NSLog(@"%@", stream.streamError); + [self disconnect]; + } else if (bytesRead == 0) { + NSLog(@"0 bytes read (end of stream encountered)."); + [self disconnect]; + } else { + [_receivedData appendBytes:buffer + length:((NSUInteger) bytesRead)]; + + // If there’s one or more full messages in there, process them. + // (Otherwise, we’ll try again when more bytes have come in.) + NSRange crlfRange = NSRangeZero(); + while (crlfRange.location != NSNotFound) { + crlfRange = [_receivedData rangeOfBytes:C_string_crlf + options:(NSDataSearchOptions) 0 + range:_receivedData.fullRange]; + if (crlfRange.location != NSNotFound) { + NSRange messageRange = NSRangeMake(0, NSRangeMax(crlfRange)); + [self handleReceivedMessage:[_receivedData subdataWithRange:messageRange]]; + [_receivedData replaceBytesInRange:messageRange + withBytes:NULL + length:0]; + } + } + } +} + +-(void) handleReceivedMessage:(NSData *)messageData { + NSLog(@"handleReceivedMessage: [%s]", messageData.terminatedCString); + NSData *prefix; + NSData *command; + NSMutableArray *params = [NSMutableArray array]; + + /******************************/ + /* State machine based parsing. + */ + + typedef NS_ENUM(NSUInteger, IRCClientMessageParsingSection) { + IRCClientMessageParsingStart, + IRCClientMessageParsingPrefix, + IRCClientMessageParsingCommand, + IRCClientMessageParsingMiddleParams, + IRCClientMessageParsingTrailingParam, + IRCClientMessageParsingEnd + }; + + IRCClientMessageParsingSection section = IRCClientMessageParsingStart; + NSUInteger sectionStart = 0; + for (NSUInteger i = 0; i < messageData.length; i++) { + char c = ((char *)(messageData.bytes))[i]; + switch (section) { + case IRCClientMessageParsingStart: + if (c == ':') + sectionStart = (i + 1); + section = (c == ':' + ? IRCClientMessageParsingPrefix + : IRCClientMessageParsingCommand); + break; + case IRCClientMessageParsingPrefix: + if (c == ' ') { + prefix = [messageData subdataWithRange:NSRangeMake(sectionStart, + i - sectionStart)]; + sectionStart = (i + 1); + section = IRCClientMessageParsingCommand; + } + break; + case IRCClientMessageParsingCommand: + if (c == ' ') { + command = [messageData subdataWithRange:NSRangeMake(sectionStart, + i - sectionStart)]; + sectionStart = (i + 1); + section = IRCClientMessageParsingMiddleParams; + } + break; + case IRCClientMessageParsingMiddleParams: + if (c == ' ') { + [params addObject:[messageData subdataWithRange:NSRangeMake(sectionStart, + i - sectionStart)]]; + sectionStart = (i + 1); + } else if (c == ':') { + sectionStart = (i + 1); + section = IRCClientMessageParsingTrailingParam; + } else if ( ((char *)(messageData.bytes))[i] == '\r' + && ((char *)(messageData.bytes))[i + 1] == '\n') { + [params addObject:[messageData subdataWithRange:NSRangeMake(sectionStart, + i - sectionStart)]]; + section = IRCClientMessageParsingEnd; + } + break; + case IRCClientMessageParsingTrailingParam: + if ( ((char *)(messageData.bytes))[i] == '\r' + && ((char *)(messageData.bytes))[i + 1] == '\n') { + [params addObject:[messageData subdataWithRange:NSRangeMake(sectionStart, + i - sectionStart)]]; + section = IRCClientMessageParsingEnd; + } + break; + case IRCClientMessageParsingEnd: + break; + } + } + + NSMutableArray *parts = [NSMutableArray array]; + [parts addObject:(prefix ?: [NSData data])]; + [parts addObject:command]; + [parts addObjectsFromArray:params]; + NSLog(@"[%@]", [[parts map:^NSString *(NSData *part) { + return [NSString stringWithFormat:@"%s", part.terminatedCString]; + }] componentsJoinedByString:@"]["]); + + [self handleIRCEvent:command + from:prefix + params:params]; + + /**********************/ + /* Range-based parsing. + */ + +// NSData *colon = [NSData dataFromCString:":"]; +// NSData *space = [NSData dataFromCString:" "]; +// NSData *crlf = [NSData dataFromCString:C_string_crlf]; +// +// NSRange remainder = messageData.fullRange; +// NSRange spaceRange; +// NSRange maybeColonRange; +// +// // Prefix. +// maybeColonRange = NSRangeMake(remainder.location, +// colon.length); +// if ([[messageData subdataWithRange:maybeColonRange] isEqualToData:colon]) { +// remainder = [messageData rangeAfterRange:maybeColonRange]; +// spaceRange = [messageData rangeOfData:space +// options:(NSDataSearchOptions) 0 +// range:remainder]; +// prefix = [messageData subdataWithRange:NSRangeMake(remainder.location, +// spaceRange.location - remainder.location)]; +// remainder = [messageData rangeAfterRange:spaceRange]; +// } +// +// // Command. +// spaceRange = [messageData rangeOfData:space +// options:(NSDataSearchOptions) 0 +// range:remainder]; +// command = [messageData subdataWithRange:NSRangeMake(remainder.location, +// spaceRange.location - remainder.location)]; +// remainder = [messageData rangeAfterRange:spaceRange]; +// +// // Params. +// while (YES) { +// maybeColonRange = NSRangeMake(remainder.location, +// colon.length); +// if ([[messageData subdataWithRange:maybeColonRange] isEqualToData:colon]) { +// // Trailing param. +// remainder = [messageData rangeAfterRange:maybeColonRange]; +// NSRange crlfRange = [messageData rangeOfData:crlf +// options:(NSDataSearchOptions) 0 +// range:remainder]; +// [params addObject:[messageData subdataWithRange:NSRangeMake(remainder.location, +// crlfRange.location - remainder.location)]]; +// break; +// } else { +// // Middle params. +// spaceRange = [messageData rangeOfData:space +// options:(NSDataSearchOptions) 0 +// range:remainder]; +// if (spaceRange.location == NSNotFound) { +// NSRange crlfRange = [messageData rangeOfData:crlf +// options:(NSDataSearchOptions) 0 +// range:remainder]; +// [params addObject:[messageData subdataWithRange:NSRangeMake(remainder.location, +// crlfRange.location - remainder.location)]]; +// break; +// } else { +// [params addObject: [messageData subdataWithRange:NSRangeMake(remainder.location, +// spaceRange.location - remainder.location)]]; +// remainder = [messageData rangeAfterRange:spaceRange]; +// if ([[messageData subdataWithRange:remainder] isEqualToData:crlf]) +// break; +// } +// } +// } +// +// [self handleIRCEvent:command +// from:prefix +// params:params]; +} + +-(void) openStream:(NSStream *)stream { + [stream scheduleInRunLoop:[NSRunLoop currentRunLoop] + forMode:NSDefaultRunLoopMode]; + [stream open]; +} + +-(void) closeStream:(NSStream *)stream { + [stream close]; + [stream removeFromRunLoop:[NSRunLoop currentRunLoop] + forMode:NSDefaultRunLoopMode]; +} + /******************************/ #pragma mark - Instance methods /******************************/ -(int) connect { - return irc_connect(_irc_session, - _server.terminatedCString, - (unsigned short) _port, - (_password.length > 0 ? _password.terminatedCString : NULL), - _nickname.terminatedCString, - _username.terminatedCString, - _realname.terminatedCString); + if (self.isConnected) + return 0; + + NSInputStream *iStream; + NSOutputStream *oStream; + [NSStream getStreamsToHostNamed:[NSString stringWithUTF8Data:_server] + port:_port + inputStream:&iStream + outputStream:&oStream]; + _iStream = iStream; + _oStream = oStream; + + _receivedData = [NSMutableData data]; + _dataToSend = [NSMutableData data]; + + // Prepare cleanup handler. + __unsafe_unretained typeof(self) weakSelf = self; + _cleanupHandler = ^void() { + _stateFlags = (IRCClientSessionStateFlags) 0; + + [weakSelf closeStream:iStream]; + [weakSelf closeStream:oStream]; + + _iStream = nil; + _oStream = nil; + + _receivedData = nil; + _dataToSend = nil; + + _cleanupHandler = nil; + }; + + // Get proxy settings from system configuration. + NSDictionary *proxySettings = CFBridgingRelease(CFNetworkCopySystemProxySettings()); + BOOL SOCKSProxyEnabled = ([proxySettings[(NSString *) kCFNetworkProxiesSOCKSEnable] integerValue] != 0); + + // TODO: Allow setting this somehow! + BOOL SSLEnabled = NO; + + // Configure and open streams. + [@[ iStream, oStream ] forEach:^(NSStream *stream) { + [stream setDelegate:self]; + if (SSLEnabled) + [stream setProperty:NSStreamSocketSecurityLevelNegotiatedSSL + forKey:NSStreamSocketSecurityLevelKey]; + if (SOCKSProxyEnabled) + [stream setProperty:proxySettings + forKey:NSStreamSOCKSProxyConfigurationKey]; + [self openStream:stream]; + }]; + + // Send PASS message (if need be). + if ( _password + && _password.length > 0) { + [self sendRaw:[NSData dataWithFormat:"PASS %@", _password, nil]]; + } + + // Send NICK message. + [self sendRaw:[NSData dataWithFormat:"NICK %@", _nickname, nil]]; + + // Send USER message. + [self sendRaw:[NSData dataWithFormat:"USER %@ unknown unknown :%@", _username, _realname, nil]]; + + return 1; } -(void) disconnect { - irc_disconnect(_irc_session); -} - --(void) run { - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - @autoreleasepool { - irc_run(_irc_session); - } - [_delegate disconnected:self]; - }); -} - --(int) setNickname:(NSData *)nickname - username:(NSData *)username - realname:(NSData *)realname { if (self.isConnected) { - return 0; + [_delegate disconnected:self]; + _cleanupHandler(); + } +} + +-(BOOL) setNickname:(NSData *)nickname + username:(NSData *)username + realname:(NSData *)realname { + if (self.isConnected) { + return NO; } else { _nickname = nickname; _username = username; _realname = realname; - return 1; + return YES; } } @@ -319,231 +643,250 @@ static NSDictionary* ircNumericCodeList; /**************************/ -(int) sendRaw:(NSData *)message { - return irc_send_raw(_irc_session, - message.terminatedCString); + dispatch_async(_q, ^{ + [_dataToSend appendData:message]; + [_dataToSend appendBytes:C_string_crlf + length:2]; + + if ([_oStream hasSpaceAvailable]) + [self sendData:_oStream]; + }); + + return 0; } -(int) quit:(NSData *)reason { - return irc_send_raw(_irc_session, - "QUIT :%s", - (reason - ? reason.terminatedCString - : "quit")); + [self sendRaw:[NSData dataWithFormat:"QUIT :%@", (reason ?: [NSData dataFromCString:"quit"]), nil]]; + + return 0; } -(int) join:(NSData *)channel key:(NSData *)key { - if (!channel || channel.length == 0) - return LIBIRC_ERR_STATE; + if ( !channel + || channel.length == 0) + return 1; +// return LIBIRC_ERR_STATE; - if (key && key.length > 0) - return irc_send_raw(_irc_session, - "JOIN %s :%s", - channel.terminatedCString, - key.terminatedCString); + if ( key + && key.length > 0) + [self sendRaw:[NSData dataWithFormat:"JOIN %@ :%@", channel, key, nil]]; else - return irc_send_raw(_irc_session, - "JOIN %s", - channel.terminatedCString); + [self sendRaw:[NSData dataWithFormat:"JOIN %@", channel, nil]]; + + return 0; } -(int) names:(NSData *)channel { if (channel) - return irc_send_raw(_irc_session, - "NAMES %s", - channel.terminatedCString); + [self sendRaw:[NSData dataWithFormat:"NAMES %@", channel, nil]]; else - return irc_send_raw(_irc_session, - "NAMES"); + [self sendRaw:[NSData dataWithFormat:"NAMES", nil]]; + + return 0; } -(int) list:(NSData *)channel { if (channel) - return irc_send_raw(_irc_session, - "LIST %s", - channel.terminatedCString); + [self sendRaw:[NSData dataWithFormat:"LIST %@", channel, nil]]; else - return irc_send_raw(_irc_session, - "LIST"); + [self sendRaw:[NSData dataWithFormat:"LIST", nil]]; + + return 0; } -(int) userMode:(NSData *)mode { if (mode) - return irc_send_raw(_irc_session, - "MODE %s %s", - _nickname.terminatedCString, - mode.terminatedCString); + [self sendRaw:[NSData dataWithFormat:"MODE %@ %@", _nickname, mode, nil]]; else - return irc_send_raw(_irc_session, - "MODE %s", - _nickname.terminatedCString); + [self sendRaw:[NSData dataWithFormat:"MODE %@", _nickname, nil]]; + + return 0; } -(int) nick:(NSData *)newnick { - if (!newnick || newnick.length == 0) - return LIBIRC_ERR_INVAL; + if ( !newnick + || newnick.length == 0) + return 1; +// return LIBIRC_ERR_INVAL; - return irc_send_raw(_irc_session, - "NICK %s", - newnick.terminatedCString); + [self sendRaw:[NSData dataWithFormat:"NICK %@", newnick, nil]]; + + return 0; } -(int) who:(NSData *)nickmask { - if (!nickmask || nickmask.length == 0) - return LIBIRC_ERR_INVAL; + if ( !nickmask + || nickmask.length == 0) + return 1; +// return LIBIRC_ERR_INVAL; - return irc_send_raw(_irc_session, - "WHO %s", - nickmask.terminatedCString); + [self sendRaw:[NSData dataWithFormat:"WHO %@", nickmask, nil]]; + + return 0; } -(int) whois:(NSData *)nick { if (!nick || nick.length == 0) - return LIBIRC_ERR_INVAL; + return 1; +// return LIBIRC_ERR_INVAL; - return irc_send_raw(_irc_session, - "WHOIS %s", - nick.terminatedCString); + [self sendRaw:[NSData dataWithFormat:"WHOIS %@", nick, nil]]; + + return 0; } -(int) message:(NSData *)message to:(NSData *)target { if ( !target || target.length == 0 || !message || message.length == 0) - return LIBIRC_ERR_STATE; + return 1; +// return LIBIRC_ERR_STATE; - return irc_send_raw(_irc_session, - "PRIVMSG %s :%s", - target.terminatedCString, -// irc_color_convert_to_mirc(message.terminatedCString)); - [self colorConvertToMIRC:message].terminatedCString); + [self sendRaw:[NSData dataWithFormat:"PRIVMSG %@ :%@", target, [self colorConvertToMIRC:message], nil]]; + + return 0; } -(int) action:(NSData *)action to:(NSData *)target { if ( !target || target.length == 0 || !action || action.length == 0) - return LIBIRC_ERR_STATE; + return 1; +// return LIBIRC_ERR_STATE; - return irc_send_raw(_irc_session, - "PRIVMSG %s :\x01" "ACTION %s\x01", - target.terminatedCString, -// irc_color_convert_to_mirc(action.terminatedCString)); - [self colorConvertToMIRC:action].terminatedCString); + [self sendRaw:[NSData dataWithFormat:"PRIVMSG %@ :\x01" "ACTION %@\x01", target, [self colorConvertToMIRC:action], nil]]; + + return 0; } -(int) notice:(NSData *)notice to:(NSData *)target { if ( !target || target.length == 0 || !notice || notice.length == 0) - return LIBIRC_ERR_STATE; + return 1; +// return LIBIRC_ERR_STATE; - return irc_send_raw(_irc_session, - "NOTICE %s :%s", - target.terminatedCString, - notice.terminatedCString); + [self sendRaw:[NSData dataWithFormat:"NOTICE %@ :%@", target, notice, nil]]; + + return 0; } -(int) ctcpRequest:(NSData *)request target:(NSData *)target { if ( !target || target.length == 0 || !request || request.length == 0) - return LIBIRC_ERR_STATE; + return 1; +// return LIBIRC_ERR_STATE; - return irc_send_raw(_irc_session, - "PRIVMSG %s :\x01%s\x01", - target.terminatedCString, - request.terminatedCString); + [self sendRaw:[NSData dataWithFormat:"PRIVMSG %@ :\x01%@\x01", target, request, nil]]; + return 0; } -(int) ctcpReply:(NSData *)reply target:(NSData *)target { if ( !target || target.length == 0 || !reply || reply.length == 0) - return LIBIRC_ERR_STATE; + return 1; +// return LIBIRC_ERR_STATE; - return irc_send_raw(_irc_session, - "NOTICE %s :\x01%s\x01", - target.terminatedCString, - reply.terminatedCString); + [self sendRaw:[NSData dataWithFormat:"NOTICE %@ :\x01%@\x01", target, reply, nil]]; + return 0; } /********************************/ #pragma mark - IRC event handlers /********************************/ --(void) ircEventReceived:(const char *)event - from:(const char *)origin - withParams:(const char **)params - count:(unsigned int)count { - typedef enum : NSUInteger { +-(NSData *) CTCPContent:(NSData *)messageBody { + NSData *ctcpQuote = [NSData dataFromCString:"\x01"]; + if (messageBody.length > 1 + && [[messageBody subdataWithRange:NSRangeMake(0, 1)] isEqualToData:ctcpQuote] + && [[messageBody subdataWithRange:NSRangeMake(messageBody.length - 1, 1)] isEqualToData:ctcpQuote]) { + return [messageBody subdataWithRange:NSRangeMake(1, messageBody.length - 2)]; + } else { + return nil; + } +} + +-(NSData *) processColorCodes:(NSData *)messageBody { + typedef NS_ENUM(NSUInteger, SA_IRC_ColorCodeHandling) { SA_IRC_ParseColorCodes, SA_IRC_StripColorCodes, SA_IRC_IgnoreColorCodes, - } SA_IRC_ColorCodeHandling; + }; // TODO: Support setting this somehow... SA_IRC_ColorCodeHandling whatAboutColors = SA_IRC_ParseColorCodes; - NSMutableArray *params_array; - if ((whatAboutColors != SA_IRC_IgnoreColorCodes) - && ( !strcmp(event, "PRIVMSG") - || !strcmp(event, "CHANMSG") - || !strcmp(event, "SERVMSG") - || !strcmp(event, "PRIVNOTICE") - || !strcmp(event, "CHANNOTICE") - || !strcmp(event, "SERVNOTICE") - || !strcmp(event, "CTCP_ACTION") - )) { - params_array = [NSMutableArray arrayWithCapacity:count]; - [NSIndexSet from:0 - for:count - do:^(NSUInteger idx) { - NSData *param = (whatAboutColors == SA_IRC_ParseColorCodes - ? [self colorConvertFromMIRC:[NSData dataFromCString:params[idx]]] - : [self colorStripFromMIRC:[NSData dataFromCString:params[idx]]]); - [params_array addObject:param]; - }]; - } else { - params_array = [NSMutableArray arrayOfCStringData:params - count:count]; + switch (whatAboutColors) { + case SA_IRC_IgnoreColorCodes: + return messageBody; + case SA_IRC_ParseColorCodes: + return [self colorConvertFromMIRC:messageBody]; + case SA_IRC_StripColorCodes: + return [self colorStripFromMIRC:messageBody]; } +} - NSData *origin_data = origin ? [NSData dataFromCString:origin] : nil; - NSData *param_0_data = (count > 0 - ? params_array[0] - : nil); - NSData *param_1_data = (count > 1 - ? params_array[1] - : nil); - NSData *param_2_data = (count > 2 - ? params_array[2] - : nil); +-(void) handleIRCEvent:(NSData *)command + from:(NSData *)origin + params:(NSArray *)params { + // This is so we can refer to “param [ 0 / 1 / 2 ] or nil” without + // having to check for out-of-range every time. + NSData *param_0 = (params.count > 0 + ? params[0] + : nil); + NSData *param_1 = (params.count > 1 + ? params[1] + : nil); + NSData *param_2 = (params.count > 2 + ? params[2] + : nil); + + // PING event. + if ([command isEqualToCString:"PING"]) { + // TODO: implement an "ignore ping" toggle + // and a "ping passthrough" toggle + [self sendRaw:[NSData dataWithFormat:"PONG %@", param_0, nil]]; - if (!strcmp(event, "CONNECT")) { - /*! - * The ‘on_connect’ event is triggered when the client successfully - * connects to the server, and could send commands to the server. - * No extra params supplied; \a params is 0. - */ - [_delegate connectionSucceeded:self]; - } else if (!strcmp(event, "PING")) { - // TODO: the part about LIBIRC_OPTION_PING_PASSTHROUGH seems to be a lie?? - // But see also LIBIRC_OPTION_IGNORE_PING??? - /*! - * The ‘ping’ event is triggered when the client receives a PING message. - * It is only generated if the LIBIRC_OPTION_PING_PASSTHROUGH option is set; - * otherwise, the library responds to PING messages automatically. - * - * \param origin the person, who generated the ping. - * \param params[0] mandatory, contains who knows what. - */ if ([_delegate respondsToSelector:@selector(ping:from:session:)]) { - [_delegate ping:param_0_data - from:origin_data + [_delegate ping:param_0 + from:origin session:self]; } - } else if (!strcmp(event, "NICK")) { + + return; + } + + // Numeric event. + if ( command.length == 3 + && isdigit(((char *) command.bytes)[0]) + && isdigit(((char *) command.bytes)[1]) + && isdigit(((char *) command.bytes)[2])) { + NSUInteger numericEventCode = (NSUInteger) atoi(command.terminatedCString); + + // RPL_WELCOME, RPL_ENDOFMOTD, or ERR_NOMOTD. + if ( ( numericEventCode == 1 + || numericEventCode == 376 + || numericEventCode == 422) + && !(_stateFlags & IRCClientSessionMOTDReceived)) { + _stateFlags |= IRCClientSessionMOTDReceived; + [_delegate connectionSucceeded:self]; + } + + if ([_delegate respondsToSelector:@selector(numericEventReceived:from:params:session:)]) { + [_delegate numericEventReceived:numericEventCode + from:origin + params:params + session:self]; + } + + return; + } + + // IRC command. + if ([command isEqualToCString:"NICK"]) { /*! * The ‘nick’ event is triggered when the client receives a NICK message, * meaning that someone (including you) on a channel with the client has @@ -552,9 +895,9 @@ static NSDictionary* ircNumericCodeList; * \param origin The person who changed their nick. Note that it can be you! * \param params[0] Mandatory; contains the new nick. */ - [self nickChangedFrom:origin_data - to:param_0_data]; - } else if (!strcmp(event, "QUIT")) { + [self nickChangedFrom:origin + to:param_0]; + } else if ([command isEqualToCString:"QUIT"]) { /*! * The ‘quit’ event is triggered upon receipt of a QUIT message, which * means that someone on a channel with the client has disconnected. @@ -562,10 +905,10 @@ static NSDictionary* ircNumericCodeList; * \param origin The person who is disconnected. * \param params[0] Optional; contains the reason message (user-specified). */ - [_delegate userQuit:origin_data - withReason:param_0_data + [_delegate userQuit:origin + withReason:param_0 session:self]; - } else if (!strcmp(event, "JOIN")) { + } else if ([command isEqualToCString:"JOIN"]) { /*! * The ‘join’ event is triggered upon receipt of a JOIN message, which * means that someone has entered a channel that the client is on. @@ -575,9 +918,9 @@ static NSDictionary* ircNumericCodeList; * command succeed. * \param params[0] Mandatory; contains the channel name. */ - [self userJoined:origin_data - channel:param_0_data]; - } else if (!strcmp(event, "PART")) { + [self userJoined:origin + channel:param_0]; + } else if ([command isEqualToCString:"PART"]) { /*! * The ‘part’ event is triggered upon receipt of a PART message, which * means that someone has left a channel that the client is on. @@ -588,41 +931,43 @@ static NSDictionary* ircNumericCodeList; * \param params[0] Mandatory; contains the channel name. * \param params[1] Optional; contains the reason message (user-defined). */ - [self userParted:origin_data - channel:param_0_data - withReason:param_1_data]; - } else if (!strcmp(event, "MODE")) { - /*! - * The ‘mode’ event is triggered upon receipt of a channel MODE message, - * which means that someone on a channel with the client has changed the - * channel’s parameters. - * - * \param origin The person who changed the channel mode. - * \param params[0] Mandatory; contains the channel name. - * \param params[1] Mandatory; contains the changed channel mode, like - * ‘+t’, ‘-i’, and so on. - * \param params[2] Optional; contains the mode argument (for example, a - * key for +k mode, or user who got channel operator status for - * +o mode) - */ - IRCClientChannel *channel = _channels[param_0_data]; - [channel modeSet:param_1_data - withParams:param_2_data - by:origin_data]; - } else if (!strcmp(event, "UMODE")) { - /*! - * The ‘umode’ event is triggered upon receipt of a user MODE message, - * which means that your user mode has been changed. - * - * \param origin The person who changed the user mode. - * \param params[0] Mandatory; contains the user changed mode, like - * ‘+t’, ‘-i’ and so on. - */ - // TODO: keep track of the user's mode on the connection? - [_delegate modeSet:param_0_data - by:origin_data - session:self]; - } else if (!strcmp(event, "TOPIC")) { + [self userParted:origin + channel:param_0 + withReason:param_1]; + } else if ([command isEqualToCString:"MODE"]) { + if ( param_0 + && [param_0 isEqualToData:_nickname]) { + /*! + * The ‘umode’ event is triggered upon receipt of a user MODE message, + * which means that your user mode has been changed. + * + * \param origin The person who changed the user mode. + * \param params[0] Mandatory; contains the user changed mode, like + * ‘+t’, ‘-i’ and so on. + */ + [_delegate modeSet:param_1 + by:origin + session:self]; + } else { + /*! + * The ‘mode’ event is triggered upon receipt of a channel MODE message, + * which means that someone on a channel with the client has changed the + * channel’s parameters. + * + * \param origin The person who changed the channel mode. + * \param params[0] Mandatory; contains the channel name. + * \param params[1] Mandatory; contains the changed channel mode, like + * ‘+t’, ‘-i’, and so on. + * \param params[2] Optional; contains the mode argument (for example, a + * key for +k mode, or user who got channel operator status for + * +o mode) + */ + IRCClientChannel *channel = _channels[param_0]; + [channel modeSet:param_1 + withParams:param_2 + by:origin]; + } + } else if ([command isEqualToCString:"TOPIC"]) { /*! * The ‘topic’ event is triggered upon receipt of a TOPIC message, which * means that someone on a channel with the client has changed the @@ -632,10 +977,10 @@ static NSDictionary* ircNumericCodeList; * \param params[0] Mandatory; contains the channel name. * \param params[1] Optional; contains the new topic. */ - IRCClientChannel *channel = _channels[param_0_data]; - [channel topicSet:param_1_data - by:origin_data]; - } else if (!strcmp(event, "KICK")) { + IRCClientChannel *channel = _channels[param_0]; + [channel topicSet:param_1 + by:origin]; + } else if ([command isEqualToCString:"KICK"]) { /*! * The ‘kick’ event is triggered upon receipt of a KICK message, which * means that someone on a channel with the client (or possibly the @@ -646,11 +991,11 @@ static NSDictionary* ircNumericCodeList; * \param params[1] Optional; contains the nick of kicked person. * \param params[2] Optional; contains the kick text. */ - [self userKicked:param_1_data - fromChannel:param_0_data - by:origin_data - withReason:param_2_data]; - } else if (!strcmp(event, "ERROR")) { + [self userKicked:param_1 + fromChannel:param_0 + by:origin + withReason:param_2]; + } else if ([command isEqualToCString:"ERROR"]) { /*! * The ‘error’ event is triggered upon receipt of an ERROR message, which * (when sent to clients) usually means the client has been disconnected. @@ -658,9 +1003,9 @@ static NSDictionary* ircNumericCodeList; * \param origin the person, who generates the message. * \param params optional, contains who knows what. */ - [_delegate errorReceived:param_0_data + [_delegate errorReceived:params session:self]; - } else if (!strcmp(event, "INVITE")) { + } else if ([command isEqualToCString:"INVITE"]) { /*! * The ‘invite’ event is triggered upon receipt of an INVITE message, * which means that someone is permitting the client’s entry into a +i @@ -672,153 +1017,184 @@ static NSDictionary* ircNumericCodeList; * * \sa irc_cmd_invite irc_cmd_chanmode_invite */ - [_delegate invitedToChannel:param_1_data - by:origin_data + [_delegate invitedToChannel:param_1 + by:origin session:self]; - } else if (!strcmp(event, "PRIVMSG")) { - /*! - * The ‘privmsg’ event is triggered upon receipt of a PRIVMSG message - * which is addressed to one or more clients, which means that someone - * is sending the client a private message. - * - * \param origin The person who generated the message. - * \param params[0] Mandatory; contains your nick. - * \param params[1] Optional; contains the message text. - */ - [_delegate privateMessageReceived:param_1_data - fromUser:origin_data - session:self]; - } else if (!strcmp(event, "CHANMSG")) { - /*! - * The ‘chanmsg’ event is triggered upon receipt of a PRIVMSG message - * to an entire channel, which means that someone on a channel with - * the client has said something aloud. Your own messages don’t trigger - * PRIVMSG event. - * - * \param origin The person who generated the message. - * \param params[0] Mandatory; contains the channel name. - * \param params[1] Optional; contains the message text. - */ - IRCClientChannel *channel = _channels[param_0_data]; - [channel messageSent:param_1_data - byUser:origin_data]; - } else if (!strcmp(event, "SERVMSG")) { - /*! - * The ‘servmsg’ event is triggered upon receipt of a PRIVMSG message - * which is addressed to no one in particular, but it sent to the client - * anyway. - * - * \param origin The person who generated the message. - * \param params Optional; contains who knows what. - */ - [_delegate serverMessageReceivedFrom:origin_data - params:params_array - session:self]; - } else if (!strcmp(event, "PRIVNOTICE")) { - /*! - * The ‘notice’ event is triggered upon receipt of a NOTICE message - * which means that someone has sent the client a public or private - * notice. According to RFC 1459, the only difference between NOTICE - * and PRIVMSG is that you should NEVER automatically reply to NOTICE - * messages. Unfortunately, this rule is frequently violated by IRC - * servers itself - for example, NICKSERV messages require reply, and - * are NOTICEs. - * - * \param origin The person who generated the message. - * \param params[0] Mandatory; contains your nick. - * \param params[1] Optional; contains the message text. - */ - [_delegate privateNoticeReceived:param_1_data - fromUser:origin_data - session:self]; - } else if (!strcmp(event, "CHANNOTICE")) { - /*! - * The ‘notice’ event is triggered upon receipt of a NOTICE message - * which means that someone has sent the client a public or private - * notice. According to RFC 1459, the only difference between NOTICE - * and PRIVMSG is that you should NEVER automatically reply to NOTICE - * messages. Unfortunately, this rule is frequently violated by IRC - * servers itself - for example, NICKSERV messages require reply, and - * are NOTICEs. - * - * \param origin The person who generated the message. - * \param params[0] Mandatory; contains the target channel name. - * \param params[1] Optional; contains the message text. - */ - IRCClientChannel *channel = _channels[param_0_data]; - [channel noticeSent:param_1_data - byUser:origin_data]; - } else if (!strcmp(event, "SERVNOTICE")) { - /*! - * The ‘server_notice’ event is triggered upon receipt of a NOTICE - * message which means that the server has sent the client a notice. - * This notice is not necessarily addressed to the client’s nick - * (for example, AUTH notices, sent before the client’s nick is known). - * According to RFC 1459, the only difference between NOTICE - * and PRIVMSG is that you should NEVER automatically reply to NOTICE - * messages. Unfortunately, this rule is frequently violated by IRC - * servers itself - for example, NICKSERV messages require reply, and - * are NOTICEs. - * - * \param origin The person who generated the message. - * \param params Optional; contains who knows what. - */ - [_delegate serverNoticeReceivedFrom:origin_data - params:params_array - session:self]; - } else if (!strcmp(event, "CTCP_REQ")) { - /*! - * The ‘ctcp’ event is triggered when the client receives the CTCP - * request. By default, the built-in CTCP request handler is used. The - * build-in handler automatically replies on most CTCP messages, so you - * will rarely need to override it. - * - * \param origin The person who generated the message. - * \param params[0] Mandatory; contains the complete CTCP message, including - * its arguments. - * - * Mirc generates PING, FINGER, VERSION, TIME and ACTION messages, - * check the source code of \c libirc_event_ctcp_internal function to - * see how to write your own CTCP request handler. Also you may find - * useful this question in FAQ: \ref faq4 - */ - [self CTCPRequestReceived:param_0_data - fromUser:origin_data]; - } else if (!strcmp(event, "CTCP_REPL")) { - /*! - * The ‘ctcp’ event is triggered when the client receives the CTCP reply. - * - * \param origin The person who generated the message. - * \param params[0] Mandatory; the CTCP message itself with its arguments. - */ - if ([_delegate respondsToSelector:@selector(CTCPReplyReceived:fromUser:session:)]) { - [_delegate CTCPReplyReceived:param_0_data - fromUser:origin_data - session:self]; - } - } else if (!strcmp(event, "CTCP_ACTION")) { - /*! - * The ‘action’ event is triggered when the client receives the CTCP - * ACTION message. These messages usually looks like:\n - * \code - * [23:32:55] * Tim gonna sleep. - * \endcode - * - * \param origin The person who generated the message. - * \param params[0] Mandatory; the target of the message. - * \param params[1] Mandatory; the ACTION message. - */ - IRCClientChannel* channel = _channels[param_0_data]; - if (channel != nil) { - // An action on a channel we’re on. - [channel actionPerformed:param_1_data - byUser:origin_data]; + } else if ([command isEqualToCString:"PRIVMSG"]) { + NSData *ctcpContent = [self CTCPContent:param_1]; + if (ctcpContent) { + NSData *dccPrefix = [NSData dataFromCString:"DCC "]; + NSData *actionPrefix = [NSData dataFromCString:"ACTION "]; + if ([[ctcpContent subdataWithRange:NSRangeMake(0, dccPrefix.length)] isEqualToData:dccPrefix]) { + // TODO: implement DCC request support! + } else if ([[ctcpContent subdataWithRange:NSRangeMake(0, actionPrefix.length)] isEqualToData:actionPrefix]) { + NSData *action = [self processColorCodes:[ctcpContent + subdataWithRange:[ctcpContent + rangeAfterRange:NSRangeMake(0, actionPrefix.length)]]]; + /*! + * The ‘action’ event is triggered when the client receives the CTCP + * ACTION message. These messages usually looks like:\n + * \code + * [23:32:55] * Tim gonna sleep. + * \endcode + * + * \param origin The person who generated the message. + * \param params[0] Mandatory; the target of the message. + * \param params[1] Mandatory; the ACTION message. + */ + IRCClientChannel* channel = _channels[param_0]; + if (channel != nil) { + // An action on a channel we’re on. + [channel actionPerformed:action + byUser:origin]; + } else { + // An action in a private message. + [_delegate privateCTCPActionReceived:action + fromUser:origin + session:self]; + } + } else { + /*! + * The ‘ctcp’ event is triggered when the client receives the CTCP + * request. By default, the built-in CTCP request handler is used. The + * build-in handler automatically replies on most CTCP messages, so you + * will rarely need to override it. + * + * \param origin The person who generated the message. + * \param params[0] Mandatory; contains the complete CTCP message, including + * its arguments. + * + * Mirc generates PING, FINGER, VERSION, TIME and ACTION messages, + * check the source code of \c libirc_event_ctcp_internal function to + * see how to write your own CTCP request handler. Also you may find + * useful this question in FAQ: \ref faq4 + */ + [self CTCPRequestReceived:ctcpContent + fromUser:origin]; + } + } else if ([param_0 isEqualToData:_nickname]) { + /*! + * The ‘privmsg’ event is triggered upon receipt of a PRIVMSG message + * which is addressed to one or more clients, which means that someone + * is sending the client a private message. + * + * \param origin The person who generated the message. + * \param params[0] Mandatory; contains your nick. + * \param params[1] Optional; contains the message text. + */ + NSData *message = [self processColorCodes:param_1]; + [_delegate privateMessageReceived:message + fromUser:origin + session:self]; + } else if ( ((char *) param_0.bytes)[0] == '#' + || ((char *) param_0.bytes)[0] == '&' + || ((char *) param_0.bytes)[0] == '!' + || ((char *) param_0.bytes)[0] == '+') { + /*! + * The ‘chanmsg’ event is triggered upon receipt of a PRIVMSG message + * to an entire channel, which means that someone on a channel with + * the client has said something aloud. Your own messages don’t trigger + * PRIVMSG event. + * + * \param origin The person who generated the message. + * \param params[0] Mandatory; contains the channel name. + * \param params[1] Optional; contains the message text. + */ + IRCClientChannel *channel = _channels[param_0]; + NSData *message = [self processColorCodes:param_1]; + [channel messageSent:message + byUser:origin]; } else { - // An action in a private message. - [_delegate privateCTCPActionReceived:param_1_data - fromUser:origin_data + /*! + * The ‘servmsg’ event is triggered upon receipt of a PRIVMSG message + * which is addressed to no one in particular, but it sent to the client + * anyway. + * + * \param origin The person who generated the message. + * \param params Optional; contains who knows what. + */ + params = [params map:^id(NSData *param) { + return [self processColorCodes:param]; + }]; + [_delegate serverMessageReceivedFrom:origin + params:params session:self]; } + } else if ([command isEqualToCString:"NOTICE"]) { + NSData *ctcpContent = [self CTCPContent:param_1]; + if (ctcpContent) { + /*! + * The ‘ctcp’ event is triggered when the client receives the CTCP reply. + * + * \param origin The person who generated the message. + * \param params[0] Mandatory; the CTCP message itself with its arguments. + */ + if ([_delegate respondsToSelector:@selector(CTCPReplyReceived:fromUser:session:)]) { + [_delegate CTCPReplyReceived:param_0 + fromUser:origin + session:self]; + } + } else if ([param_0 isEqualToData:_nickname]) { + /*! + * The ‘notice’ event is triggered upon receipt of a NOTICE message + * which means that someone has sent the client a public or private + * notice. According to RFC 1459, the only difference between NOTICE + * and PRIVMSG is that you should NEVER automatically reply to NOTICE + * messages. Unfortunately, this rule is frequently violated by IRC + * servers itself - for example, NICKSERV messages require reply, and + * are NOTICEs. + * + * \param origin The person who generated the message. + * \param params[0] Mandatory; contains your nick. + * \param params[1] Optional; contains the message text. + */ + NSData *notice = [self processColorCodes:param_1]; + [_delegate privateNoticeReceived:notice + fromUser:origin + session:self]; + } else if ( ((char *) param_0.bytes)[0] == '#' + || ((char *) param_0.bytes)[0] == '&' + || ((char *) param_0.bytes)[0] == '!' + || ((char *) param_0.bytes)[0] == '+') { + /*! + * The ‘notice’ event is triggered upon receipt of a NOTICE message + * which means that someone has sent the client a public or private + * notice. According to RFC 1459, the only difference between NOTICE + * and PRIVMSG is that you should NEVER automatically reply to NOTICE + * messages. Unfortunately, this rule is frequently violated by IRC + * servers itself - for example, NICKSERV messages require reply, and + * are NOTICEs. + * + * \param origin The person who generated the message. + * \param params[0] Mandatory; contains the target channel name. + * \param params[1] Optional; contains the message text. + */ + IRCClientChannel *channel = _channels[param_0]; + NSData *notice = [self processColorCodes:param_1]; + [channel noticeSent:notice + byUser:origin]; + } else { + /*! + * The ‘server_notice’ event is triggered upon receipt of a NOTICE + * message which means that the server has sent the client a notice. + * This notice is not necessarily addressed to the client’s nick + * (for example, AUTH notices, sent before the client’s nick is known). + * According to RFC 1459, the only difference between NOTICE + * and PRIVMSG is that you should NEVER automatically reply to NOTICE + * messages. Unfortunately, this rule is frequently violated by IRC + * servers itself - for example, NICKSERV messages require reply, and + * are NOTICEs. + * + * \param origin The person who generated the message. + * \param params Optional; contains who knows what. + */ + params = [params map:^id(NSData *param) { + return [self processColorCodes:param]; + }]; + [_delegate serverNoticeReceivedFrom:origin + params:params + session:self]; + } } else { /*! * The ‘unknown’ event is triggered upon receipt of any number of @@ -826,25 +1202,14 @@ static NSDictionary* ircNumericCodeList; * library. */ if ([_delegate respondsToSelector:@selector(unknownEventReceived:from:params:session:)]) { - [_delegate unknownEventReceived:[NSData dataFromCString:event] - from:origin_data - params:params_array + [_delegate unknownEventReceived:command + from:origin + params:params session:self]; } } } --(void) numericEventReceived:(NSUInteger)event - from:(NSData *)origin - params:(NSArray *)params { - if ([_delegate respondsToSelector:@selector(numericEventReceived:from:params:session:)]) { - [_delegate numericEventReceived:event - from:origin - params:params - session:self]; - } -} - /******************************************/ #pragma mark - Event handler helper methods /******************************************/ @@ -874,9 +1239,9 @@ static NSDictionary* ircNumericCodeList; if ([_nickname isEqualToData:nickOnly]) { // We just joined a channel; allocate an IRCClientChannel object and // add it to our channels list. - - IRCClientChannel* newChannel = [[IRCClientChannel alloc] initWithName:channelName - andIRCSession:_irc_session]; + + IRCClientChannel* newChannel = [[IRCClientChannel alloc] initWithName:channelName + andIRCSession:self]; _channels[channelName] = newChannel; [_delegate joinedNewChannel:newChannel session:self]; @@ -939,29 +1304,16 @@ static NSDictionary* ircNumericCodeList; fromUser:(NSData *)nick { NSData *nickOnly = [IRCClientSession nickFromNickUserHost:nick]; - if (!strncmp(request.terminatedCString, "PING", 4)) { + if ([request isEqualToCString:"PING"]) { [self ctcpReply:request target:nickOnly]; - } else if (!strcmp(request.terminatedCString, "VERSION")) { - const char *versionFormat = "VERSION %s"; - NSMutableData* versionReply = [NSMutableData dataWithLength:(strlen(versionFormat) + (_version.length - 2))]; - sprintf(versionReply.mutableBytes, - versionFormat, - _version.terminatedCString); - - [self ctcpReply:versionReply + } else if ([request isEqualToCString:"VERSION"]) { + [self ctcpReply:[NSData dataWithFormat:"VERSION %@", _version, nil] target:nickOnly]; - } else if (!strcmp(request.terminatedCString, "FINGER")) { - const char *fingerFormat = "FINGER %s (%s) Idle 0 seconds)"; - NSMutableData* fingerReply = [NSMutableData dataWithLength:(strlen(fingerFormat) + (_username.length - 2) + (_realname.length - 2))]; - sprintf(fingerReply.mutableBytes, - fingerFormat, - _username.terminatedCString, - _realname.terminatedCString); - - [self ctcpReply:fingerReply + } else if ([request isEqualToCString:"FINGER"]) { + [self ctcpReply:[NSData dataWithFormat:"FINGER %s (%s) Idle 0 seconds)", _username, _realname, nil] target:nickOnly]; - } else if (!strcmp(request.terminatedCString, "TIME")) { + } else if ([request isEqualToCString:"TIME"]) { time_t current_time; char timestamp[40]; struct tm *time_info; @@ -975,23 +1327,23 @@ static NSDictionary* ircNumericCodeList; target:nickOnly]; } else { if ([_delegate respondsToSelector:@selector(CTCPRequestReceived:ofType:fromUser:session:)]) { - NSRange rangeOfFirstSpace = [request rangeOfData:[NSData dataFromCString:" "] + NSData *space = [NSData dataFromCString:" "]; + NSRange rangeOfFirstSpace = [request rangeOfData:space options:(NSDataSearchOptions) 0 - range:NSRangeMake(0, request.length)]; + range:request.fullRange]; NSRange rangeOfSecondSpace = (rangeOfFirstSpace.location != NSNotFound - ? [request rangeOfData:[NSData dataFromCString:" "] - options:(NSDataSearchOptions) 0 - range:NSRangeMake(rangeOfFirstSpace.location + 1, - request.length - (rangeOfFirstSpace.location + 1))] + ? [request rangeOfData:space + options:(NSDataSearchOptions) 0 + range:[request rangeAfterRange:rangeOfFirstSpace]] : NSRangeMake(NSNotFound, 0)); NSData *requestTypeData = (rangeOfFirstSpace.location != NSNotFound ? [request subdataWithRange:NSRangeMake(0, rangeOfFirstSpace.location)] : request); NSData *requestBodyData = (rangeOfSecondSpace.location != NSNotFound - ? [request subdataWithRange:NSRangeMake(rangeOfFirstSpace.location + 1, - rangeOfSecondSpace.location - (rangeOfFirstSpace.location + 1))] + ? [request subdataWithRange:NSRangeMake(rangeOfFirstSpace.location + space.length, + rangeOfSecondSpace.location - (rangeOfFirstSpace.location + space.length))] : nil); [_delegate CTCPRequestReceived:requestBodyData @@ -1008,46 +1360,6 @@ static NSDictionary* ircNumericCodeList; #pragma mark - Callback function implementations /***********************************************/ -static void onEvent(irc_session_t *session, - const char *event, - const char *origin, - const char **params, - unsigned int count) { - @autoreleasepool { - [(__bridge IRCClientSession *) irc_get_ctx(session) ircEventReceived:event - from:origin - withParams:params - count:count]; - } -} - -/*! - * The ‘numeric’ event is triggered upon receipt of any numeric response - * from the server. There is a lot of such responses, see the full list - * here: \ref rfcnumbers. - * - * \param session the session, which generates an event - * \param event the numeric code of the event. Useful in case you use a - * single event handler for several events simultaneously. - * \param origin the originator of the event. See the note below. - * \param params a list of event params. Depending on the event nature, it - * could have zero or more params. The actual number of params - * is specified in count. None of the params can be NULL, but - * ‘params’ pointer itself could be NULL for some events. - * \param count the total number of params supplied. - */ -static void onNumericEvent(irc_session_t *session, - unsigned int event, - const char *origin, - const char **params, - unsigned int count) { - @autoreleasepool { - [(__bridge IRCClientSession *) irc_get_ctx(session) numericEventReceived:event - from:[NSData dataFromCString:origin] - params:[NSArray arrayOfCStringData:params - count:count]]; - } -} /*! * The ‘dcc chat’ event is triggered when someone requests a DCC CHAT from @@ -1059,12 +1371,12 @@ static void onNumericEvent(irc_session_t *session, * \param dccid an id associated with this request. Use it in calls to * irc_dcc_accept() or irc_dcc_decline(). */ -static void onDCCChatRequest(irc_session_t *session, - const char *nick, - const char *addr, - irc_dcc_t dccid) { - // TODO: figure out what to do here??? -} +//static void onDCCChatRequest(irc_session_t *session, +// const char *nick, +// const char *addr, +// irc_dcc_t dccid) { +// // TODO: figure out what to do here??? +//} /*! * The ‘dcc send’ event is triggered when someone wants to send a file @@ -1078,11 +1390,11 @@ static void onDCCChatRequest(irc_session_t *session, * \param dccid an id associated with this request. Use it in calls to * irc_dcc_accept() or irc_dcc_decline(). */ -static void onDCCSendRequest(irc_session_t *session, - const char *nick, - const char *addr, - const char *filename, - size_t size, - irc_dcc_t dccid) { - // TODO: figure out what to do here??? -} +//static void onDCCSendRequest(irc_session_t *session, +// const char *nick, +// const char *addr, +// const char *filename, +// size_t size, +// irc_dcc_t dccid) { +// // TODO: figure out what to do here??? +//} diff --git a/IRCClient/IRCClientSessionDelegate.h b/IRCClient/IRCClientSessionDelegate.h index 9959de7..959d955 100644 --- a/IRCClient/IRCClientSessionDelegate.h +++ b/IRCClient/IRCClientSessionDelegate.h @@ -97,7 +97,7 @@ /** The client has received an ERROR message from the server. */ @required --(void) errorReceived:(NSData *)error +-(void) errorReceived:(NSArray *)params session:(IRCClientSession *)session; /** The client has received a private PRIVMSG from another IRC client. @@ -127,7 +127,7 @@ */ @required -(void) serverMessageReceivedFrom:(NSData *)origin - params:(NSArray *)params + params:(NSArray *)params session:(IRCClientSession *)session; /** The client has received a private NOTICE from the server. @@ -137,7 +137,7 @@ */ @required -(void) serverNoticeReceivedFrom:(NSData *)origin - params:(NSArray *)params + params:(NSArray *)params session:(IRCClientSession *)session; /** The IRC client has been invited to a channel. @@ -193,7 +193,7 @@ @optional -(void) numericEventReceived:(NSUInteger)event from:(NSData *)origin - params:(NSArray *)params + params:(NSArray *)params session:(IRCClientSession *)session; /** An unhandled event was received from the IRC server. @@ -205,7 +205,7 @@ @optional -(void) unknownEventReceived:(NSData *)event from:(NSData *)origin - params:(NSArray *)params + params:(NSArray *)params session:(IRCClientSession *)session; @end diff --git a/IRCClient/Info.plist b/IRCClient/Info.plist index fccda49..278eb43 100644 --- a/IRCClient/Info.plist +++ b/IRCClient/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 2.0 + 2.1a1 CFBundleSignature ???? CFBundleVersion diff --git a/README.md b/README.md index c035c99..c3d37b3 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -This is a modified version of the IRCClient framework by Nathan Ollerenshaw. It uses the libircclient library by Georgy Yunaev. (See LICENSE for more info.) I’ve rewritten it to allow robust support for arbitrary text encodings, and fixed various other problems. The original version of IRCClient, as well as libircclient, is available here: [http://sourceforge.net/projects/libircclient/](http://sourceforge.net/projects/libircclient/). +This is a modified version of the IRCClient framework by Nathan Ollerenshaw. It is partly based on the libircclient library by Georgy Yunaev. (See LICENSE for more info.) I’ve rewritten it to allow robust support for arbitrary text encodings, and fixed various other problems, as well making it fully Objective C native code. The original version of IRCClient, as well as libircclient, is available here: [http://sourceforge.net/projects/libircclient/](http://sourceforge.net/projects/libircclient/). --- @@ -57,8 +57,8 @@ handle all of the events generated by the server, and an `IRCClientChannelDelega to handle all of the events generated by channels on that server. You then create an `IRCClientSession` object in your code, assign the required -properties, and call `-[connect:]` to connect to the server and `-[run:]` to place -the connection on a new event queue and start receiving events. For example: +properties, and call `-[connect:]` to connect to the server, place the connection +on a new event queue and start receiving events. For example: ``` IRCClientSession *session = [IRCClientSession session]; @@ -73,8 +73,6 @@ session.port = 6667; username:@"test".dataAsUTF8 realname:@"test".dataAsUTF8]; [session connect]; - -[session run]; // Activates the event queue ``` If you have questions, bug reports, or suggestions regarding IRCClient, diff --git a/libircclient/include/config.h b/libircclient/include/config.h deleted file mode 100644 index f61d11b..0000000 --- a/libircclient/include/config.h +++ /dev/null @@ -1,110 +0,0 @@ -/* src/config.h. Generated from config.h.in by configure. */ -/* include/config.h.in. Generated from configure.in by autoheader. */ - -/* Define to 1 if you have the `getaddrinfo' function. */ -/* #undef HAVE_GETADDRINFO */ - -/* Define to 1 if you have the `gethostbyname_r' function. */ -/* #undef HAVE_GETHOSTBYNAME_R */ - -/* Define to 1 if you have the `inet_ntoa' function. */ -#define HAVE_INET_NTOA 1 - -/* Define to 1 if you have the `inet_pton' function. */ -/* #undef HAVE_INET_PTON */ - -/* Define to 1 if you have the header file. */ -#define HAVE_INTTYPES_H 1 - -/* Define to 1 if you have the `localtime_r' function. */ -#define HAVE_LOCALTIME_R 1 - -/* Define to 1 if your system has a GNU libc compatible `malloc' function, and - to 0 otherwise. */ -#define HAVE_MALLOC 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_MEMORY_H 1 - -/* Define to 1 if you have the `socket' function. */ -#define HAVE_SOCKET 1 - -/* Define to 1 if `stat' has the bug that it succeeds when given the - zero-length file name argument. */ -/* #undef HAVE_STAT_EMPTY_STRING_BUG */ - -/* Define to 1 if stdbool.h conforms to C99. */ -#define HAVE_STDBOOL_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDINT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDLIB_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STRINGS_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STRING_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_SELECT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_SOCKET_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_STAT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_TYPES_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_UNISTD_H 1 - -/* Define to 1 if the system has the type `_Bool'. */ -#define HAVE__BOOL 1 - -/* Define to 1 if `lstat' dereferences a symlink specified with a trailing - slash. */ -/* #undef LSTAT_FOLLOWS_SLASHED_SYMLINK */ - -/* Define to the address where bug reports for this package should be sent. */ -#define PACKAGE_BUGREPORT "gyunaev@ulduzsoft.com" - -/* Define to the full name of this package. */ -#define PACKAGE_NAME "libircclient" - -/* Define to the full name and version of this package. */ -#define PACKAGE_STRING "libircclient 1.3" - -/* Define to the one symbol short name of this package. */ -#define PACKAGE_TARNAME "libircclient" - -/* Define to the version of this package. */ -#define PACKAGE_VERSION "1.3" - -/* Define to the type of arg 1 for `select'. */ -#define SELECT_TYPE_ARG1 int - -/* Define to the type of args 2, 3 and 4 for `select'. */ -#define SELECT_TYPE_ARG234 (fd_set *) - -/* Define to the type of arg 5 for `select'. */ -#define SELECT_TYPE_ARG5 (struct timeval *) - -/* Define to 1 if you have the ANSI C header files. */ -#define STDC_HEADERS 1 - -/* Define to 1 if you can safely include both and . */ -#define TIME_WITH_SYS_TIME 1 - -/* Define to empty if `const' does not conform to ANSI C. */ -/* #undef const */ - -/* Define to rpl_malloc if the replacement function should be used. */ -/* #undef malloc */ - -/* Define to `unsigned int' if does not define. */ -/* #undef size_t */ diff --git a/libircclient/include/dcc.h b/libircclient/include/dcc.h deleted file mode 100644 index 5707350..0000000 --- a/libircclient/include/dcc.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2004-2012 George Yunaev gyunaev@ulduzsoft.com - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 3 of the License, or (at your - * option) any later version. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public - * License for more details. - */ - -#ifndef INCLUDE_IRC_DCC_H -#define INCLUDE_IRC_DCC_H - - -/* - * This structure keeps the state of a single DCC connection. - */ -struct irc_dcc_session_s { - irc_dcc_session_t * next; - - irc_dcc_t id; - void * ctx; - socket_t sock; /*!< DCC socket */ - int dccmode; /*!< Boolean value to differ chat vs send - requests. Changes the cb behavior - when - it is chat, data is sent by lines with - stripped CRLFs. In file mode, the data - is sent as-is */ - int state; - time_t timeout; - - FILE * dccsend_file_fp; - size_t received_file_size; - size_t file_confirm_offset; - - struct sockaddr_in remote_addr; - - char incoming_buf[LIBIRC_DCC_BUFFER_SIZE]; - size_t incoming_offset; - - char outgoing_buf[LIBIRC_DCC_BUFFER_SIZE]; - size_t outgoing_offset; - port_mutex_t mutex_outbuf; - - irc_dcc_callback_t cb; -}; - - -#endif /* INCLUDE_IRC_DCC_H */ diff --git a/libircclient/include/libirc_errors.h b/libircclient/include/libirc_errors.h deleted file mode 100644 index f627fbb..0000000 --- a/libircclient/include/libirc_errors.h +++ /dev/null @@ -1,235 +0,0 @@ -/* - * Copyright (C) 2004-2012 George Yunaev gyunaev@ulduzsoft.com - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 3 of the License, or (at your - * option) any later version. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public - * License for more details. - */ - -#ifndef INCLUDE_IRC_ERRORS_H -#define INCLUDE_IRC_ERRORS_H - -#ifndef IN_INCLUDE_LIBIRC_H - #error This file should not be included directly, include just libircclient.h -#endif - - -/*! brief No error - * \ingroup errorcodes - */ -#define LIBIRC_ERR_OK 0 - - -/*! \brief Invalid argument - * - * An invalid value was given for one of the arguments to a function. - * For example, supplying the NULL value for \a channel argument of - * irc_cmd_join() produces LIBIRC_ERR_INVAL error. You should fix the code. - * - * \ingroup errorcodes - */ -#define LIBIRC_ERR_INVAL 1 - - -/*! \brief Could not resolve host. - * - * The host name supplied for irc_connect() function could not be resolved - * into valid IP address. Usually means that host name is invalid. - * - * \ingroup errorcodes - */ -#define LIBIRC_ERR_RESOLV 2 - - -/*! \brief Could not create socket. - * - * The new socket could not be created or made non-blocking. Usually means - * that the server is out of resources, or (rarely :) a bug in libircclient. - * - * \ingroup errorcodes - */ -#define LIBIRC_ERR_SOCKET 3 - - -/*! \brief Could not connect. - * - * The socket could not connect to the IRC server, or to the destination DCC - * part. Usually means that either the IRC server is down or its address is - * invalid. For DCC the reason usually is the firewall on your or destination - * computer, which refuses DCC transfer. - * - * \sa irc_run irc_connect - * \ingroup errorcodes - */ -#define LIBIRC_ERR_CONNECT 4 - - -/*! \brief Connection closed by remote peer. - * - * The IRC connection was closed by the IRC server (which could mean that an - * IRC operator just have banned you from the server :)), or the DCC connection - * was closed by remote peer - for example, the other side just quits his mIrc. - * Usually it is not an error. - * - * \sa irc_run irc_connect irc_dcc_callback_t - * \ingroup errorcodes - */ -#define LIBIRC_ERR_CLOSED 5 - - -/*! \brief Out of memory - * - * There are two possible reasons for this error. First is that memory could - * not be allocated for libircclient use, and this error usually is fatal. - * Second reason is that the command queue (which keeps command ready to be - * sent to the IRC server) is full, and could not accept more commands yet. - * In this case you should just wait, and repeat the command later. - * - * \ingroup errorcodes - */ -#define LIBIRC_ERR_NOMEM 6 - - -/*! \brief Could not accept new connection - * - * A DCC chat/send connection from the remote peer could not be accepted. - * Either the connection was just terminated before it is accepted, or there - * is a bug in libircclient. - * - * \ingroup errorcodes - */ -#define LIBIRC_ERR_ACCEPT 7 - - -/*! \brief Could not send this - * - * A \a filename supplied to irc_dcc_sendfile() could not be sent. Either is - * is not a file (a directory or a socket, for example), or it is not readable. * - * - * \sa LIBIRC_ERR_OPENFILE - * \ingroup errorcodes - */ -#define LIBIRC_ERR_NODCCSEND 9 - - -/*! \brief Could not read DCC file or socket - * - * Either a DCC file could not be read (for example, was truncated during - * sending), or a DCC socket returns a read error, which usually means that - * the network connection is terminated. - * - * \ingroup errorcodes - */ -#define LIBIRC_ERR_READ 10 - - -/*! \brief Could not write DCC file or socket - * - * Either a DCC file could not be written (for example, there is no free space - * on disk), or a DCC socket returns a write error, which usually means that - * the network connection is terminated. - * - * \ingroup errorcodes - */ -#define LIBIRC_ERR_WRITE 11 - - -/*! \brief Invalid state - * - * The function is called when it is not allowed to be called. For example, - * irc_cmd_join() was called before the connection to IRC server succeed, and - * ::event_connect is called. - * - * \ingroup errorcodes - */ -#define LIBIRC_ERR_STATE 12 - - -/*! \brief Operation timed out - * - * The DCC request is timed out. - * There is a timer for each DCC request, which tracks connecting, accepting - * and non-accepted/declined DCC requests. For every request this timer - * is currently 60 seconds. If the DCC request was not connected, accepted - * or declined during this time, it will be terminated with this error. - * - * \ingroup errorcodes - */ -#define LIBIRC_ERR_TIMEOUT 13 - - -/*! \brief Could not open file for DCC send - * - * The file specified in irc_dcc_sendfile() could not be opened. - * - * \ingroup errorcodes - */ -#define LIBIRC_ERR_OPENFILE 14 - - -/*! \brief IRC server connection terminated - * - * The connection to the IRC server was terminated - possibly, by network - * error. Try to irc_connect() again. - * - * \ingroup errorcodes - */ -#define LIBIRC_ERR_TERMINATED 15 - - -/*! \brief IPv6 not supported - * - * The function which requires IPv6 support was called, but the IPv6 support was not compiled - * into the application - * - * \ingroup errorcodes - */ -#define LIBIRC_ERR_NOIPV6 16 - - -/*! \brief SSL not supported - * - * The SSL connection was required but the library was not compiled with SSL support - * - * \ingroup errorcodes - */ -#define LIBIRC_ERR_SSL_NOT_SUPPORTED 17 - - -/*! \brief SSL initialization failed - * - * The SSL connection was required but the library was not compiled with SSL support - * - * \ingroup errorcodes - */ -#define LIBIRC_ERR_SSL_INIT_FAILED 18 - - -/*! \brief SSL connection failed - * - * SSL handshare failed when attempting to connect to the server. Typically this means you're trying - * to use SSL but attempting to connect to a non-SSL port. - * \ingroup errorcodes - */ -#define LIBIRC_ERR_CONNECT_SSL_FAILED 19 - - -/*! \brief SSL certificate verify failed - * - * The server is using the self-signed certificate. Use LIBIRC_OPTION_SSL_NO_VERIFY option to connect to it. - * \ingroup errorcodes - */ -#define LIBIRC_ERR_SSL_CERT_VERIFY_FAILED 20 - - -// Internal max error value count. -// If you added more errors, add them to errors.c too! -#define LIBIRC_ERR_MAX 21 - -#endif /* INCLUDE_IRC_ERRORS_H */ diff --git a/libircclient/include/libirc_events.h b/libircclient/include/libirc_events.h deleted file mode 100644 index beb25e5..0000000 --- a/libircclient/include/libirc_events.h +++ /dev/null @@ -1,434 +0,0 @@ -/* - * Copyright (C) 2004-2012 George Yunaev gyunaev@ulduzsoft.com - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 3 of the License, or (at your - * option) any later version. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public - * License for more details. - */ - - -#ifndef INCLUDE_IRC_EVENTS_H -#define INCLUDE_IRC_EVENTS_H - - -#ifndef IN_INCLUDE_LIBIRC_H - #error This file should not be included directly, include just libircclient.h -#endif - - - -/*! - * \fn typedef void (*irc_event_callback_t) (irc_session_t * session, const char * event, const char * origin, const char ** params, unsigned int count) - * \brief A most common event callback - * - * \param session the session, which generates an event - * \param event the text name of the event. Useful in case you use a single - * event handler for several events simultaneously. - * \param origin the originator of the event. See the note below. - * \param params a list of event params. Depending on the event nature, it - * could have zero or more params. The actual number of params - * is specified in count. None of the params can be NULL, but - * 'params' pointer itself could be NULL for some events. - * \param count the total number of params supplied. - * - * Every event generates a callback. This callback is generated by most events. - * Depending on the event nature, it can provide zero or more params. For each - * event, the number of provided params is fixed, and their meaning is - * described. - * - * Every event has origin, though the \a origin variable may be NULL, which - * means that event origin is unknown. The origin usually looks like - * nick!host\@ircserver, i.e. like tim!home\@irc.krasnogorsk.ru. Such origins - * can not be used in IRC commands, and need to be stripped (i.e. host and - * server part should be cut off) before using. This can be done either - * explicitly, by calling irc_target_get_nick(), or implicitly for all the - * events - by setting the #LIBIRC_OPTION_STRIPNICKS option with irc_option_set(). - * - * \ingroup events - */ -typedef void (*irc_event_callback_t) (irc_session_t *session, const char *event, const char *origin, const char **params, unsigned int count); - - -/*! - * \fn typedef void (*irc_eventcode_callback_t) (irc_session_t * session, unsigned int event, const char * origin, const char ** params, unsigned int count) - * \brief A numeric event callback - * - * \param session the session, which generates an event - * \param event the numeric code of the event. Useful in case you use a - * single event handler for several events simultaneously. - * \param origin the originator of the event. See the note below. - * \param params a list of event params. Depending on the event nature, it - * could have zero or more params. The actual number of params - * is specified in count. None of the params can be NULL, but - * 'params' pointer itself could be NULL for some events. - * \param count the total number of params supplied. - * - * Most times in reply to your actions the IRC server generates numeric - * callbacks. Most of them are error codes, and some of them mark list start - * and list stop markers. Every code has its own set of params; for details - * you can either experiment, or read RFC 1459. - * - * Every event has origin, though the \a origin variable may be NULL, which - * means that event origin is unknown. The origin usually looks like - * nick!host\@ircserver, i.e. like tim!home\@irc.krasnogorsk.ru. Such origins - * can not be used in IRC commands, and need to be stripped (i.e. host and - * server part should be cut off) before using. This can be done either - * explicitly, by calling irc_target_get_nick(), or implicitly for all the - * events - by setting the #LIBIRC_OPTION_STRIPNICKS option with irc_option_set(). - * - * \ingroup events - */ -typedef void (*irc_eventcode_callback_t) (irc_session_t *session, unsigned int event, const char *origin, const char **params, unsigned int count); - - -/*! - * \fn typedef void (*irc_event_dcc_chat_t) (irc_session_t * session, const char * nick, const char * addr, irc_dcc_t dccid) - * \brief A remote DCC CHAT request callback - * - * \param session the session, which generates an event - * \param nick the person who requested DCC CHAT with you. - * \param addr the person's IP address in decimal-dot notation. - * \param dccid an id associated with this request. Use it in calls to - * irc_dcc_accept() or irc_dcc_decline(). - * - * This callback is called when someone requests DCC CHAT with you. In respond - * you should call either irc_dcc_accept() to accept chat request, or - * irc_dcc_decline() to decline chat request. - * - * \sa irc_dcc_accept or irc_dcc_decline - * \ingroup events - */ -typedef void (*irc_event_dcc_chat_t) (irc_session_t *session, const char *nick, const char *addr, irc_dcc_t dccid); - - -/*! - * \fn typedef void (*irc_event_dcc_send_t) (irc_session_t * session, const char * nick, const char * addr, const char * filename, unsigned long size, irc_dcc_t dccid) - * \brief A remote DCC SEND request callback - * - * \param session the session, which generates an event - * \param nick the person who requested DCC SEND to you. - * \param addr the person's IP address in decimal-dot notation. - * \param filename the sent filename. - * \param size the filename size. - * \param dccid an id associated with this request. Use it in calls to - * irc_dcc_accept() or irc_dcc_decline(). - * - * This callback is called when someone wants to send a file to you using - * DCC SEND. As with chat, in respond you should call either irc_dcc_accept() - * to accept this request and receive the file, or irc_dcc_decline() to - * decline this request. - * - * \sa irc_dcc_accept or irc_dcc_decline - * \ingroup events - */ -typedef void (*irc_event_dcc_send_t) (irc_session_t *session, const char *nick, const char *addr, const char *filename, size_t size, irc_dcc_t dccid); - - -/*! \brief Event callbacks structure. - * - * All the communication with the IRC network is based on events. Generally - * speaking, event is anything generated by someone else in the network, - * or by the IRC server itself. "Someone sends you a message", "Someone - * has joined the channel", "Someone has quits IRC" - all these messages - * are events. - * - * Every event has its own event handler, which is called when the - * appropriate event is received. You don't have to define all the event - * handlers; define only the handlers for the events you need to intercept. - * - * Most event callbacks are the types of ::irc_event_callback_t. There are - * also events, which generate ::irc_eventcode_callback_t, - * ::irc_event_dcc_chat_t and ::irc_event_dcc_send_t callbacks. - * - * \ingroup events - */ -typedef struct -{ - /*! - * The "on_connect" event is triggered when the client successfully - * connects to the server, and could send commands to the server. - * No extra params supplied; \a params is 0. - */ - irc_event_callback_t event_connect; - - /*! - * The "ping" event is triggered when the client receives a PING message. - * It is only generated if the LIBIRC_OPTION_PING_PASSTHROUGH option is set; - * otherwise, the library responds to PING messages automatically. - * - * \param origin the person, who generated the ping. - * \param params[0] mandatory, contains who knows what. - */ - irc_event_callback_t event_ping; - - /*! - * The "nick" event is triggered when the client receives a NICK message, - * meaning that someone (including you) on a channel with the client has - * changed their nickname. - * - * \param origin the person, who changes the nick. Note that it can be you! - * \param params[0] mandatory, contains the new nick. - */ - irc_event_callback_t event_nick; - - /*! - * The "quit" event is triggered upon receipt of a QUIT message, which - * means that someone on a channel with the client has disconnected. - * - * \param origin the person, who is disconnected - * \param params[0] optional, contains the reason message (user-specified). - */ - irc_event_callback_t event_quit; - - /*! - * The "join" event is triggered upon receipt of a JOIN message, which - * means that someone has entered a channel that the client is on. - * - * \param origin the person, who joins the channel. By comparing it with - * your own nickname, you can check whether your JOIN - * command succeed. - * \param params[0] mandatory, contains the channel name. - */ - irc_event_callback_t event_join; - - /*! - * The "part" event is triggered upon receipt of a PART message, which - * means that someone has left a channel that the client is on. - * - * \param origin the person, who leaves the channel. By comparing it with - * your own nickname, you can check whether your PART - * command succeed. - * \param params[0] mandatory, contains the channel name. - * \param params[1] optional, contains the reason message (user-defined). - */ - irc_event_callback_t event_part; - - /*! - * The "mode" event is triggered upon receipt of a channel MODE message, - * which means that someone on a channel with the client has changed the - * channel's parameters. - * - * \param origin the person, who changed the channel mode. - * \param params[0] mandatory, contains the channel name. - * \param params[1] mandatory, contains the changed channel mode, like - * '+t', '-i' and so on. - * \param params[2] optional, contains the mode argument (for example, a - * key for +k mode, or user who got the channel operator status for - * +o mode) - */ - irc_event_callback_t event_mode; - - /*! - * The "umode" event is triggered upon receipt of a user MODE message, - * which means that your user mode has been changed. - * - * \param origin the person, who changed the channel mode. - * \param params[0] mandatory, contains the user changed mode, like - * '+t', '-i' and so on. - */ - irc_event_callback_t event_umode; - - /*! - * The "topic" event is triggered upon receipt of a TOPIC message, which - * means that someone on a channel with the client has changed the - * channel's topic. - * - * \param origin the person, who changes the channel topic. - * \param params[0] mandatory, contains the channel name. - * \param params[1] optional, contains the new topic. - */ - irc_event_callback_t event_topic; - - /*! - * The "kick" event is triggered upon receipt of a KICK message, which - * means that someone on a channel with the client (or possibly the - * client itself!) has been forcibly ejected. - * - * \param origin the person, who kicked the poor. - * \param params[0] mandatory, contains the channel name. - * \param params[0] optional, contains the nick of kicked person. - * \param params[1] optional, contains the kick text - */ - irc_event_callback_t event_kick; - - /*! - * The "error" event is triggered upon receipt of an ERROR message, which - * (when sent to clients) usually means the client has been disconnected. - * - * \param origin the person, who generates the message. - * \param params optional, contains who knows what. - */ - irc_event_callback_t event_error; - - /*! - * The "channel" event is triggered upon receipt of a PRIVMSG message - * to an entire channel, which means that someone on a channel with - * the client has said something aloud. Your own messages don't trigger - * PRIVMSG event. - * - * \param origin the person, who generates the message. - * \param params[0] mandatory, contains the channel name. - * \param params[1] optional, contains the message text - */ - irc_event_callback_t event_channel; - - /*! - * The "privmsg" event is triggered upon receipt of a PRIVMSG message - * which is addressed to one or more clients, which means that someone - * is sending the client a private message. - * - * \param origin the person, who generates the message. - * \param params[0] mandatory, contains your nick. - * \param params[1] optional, contains the message text - */ - irc_event_callback_t event_privmsg; - - /*! - * The "privmsg" event is triggered upon receipt of a PRIVMSG message - * which is addressed to no one in particular, but it sent to the client - * anyway. - * - * \param origin the person, who generates the message. - * \param params optional, contains who knows what. - */ - irc_event_callback_t event_server_msg; - - /*! - * The "notice" event is triggered upon receipt of a NOTICE message - * which means that someone has sent the client a public or private - * notice. According to RFC 1459, the only difference between NOTICE - * and PRIVMSG is that you should NEVER automatically reply to NOTICE - * messages. Unfortunately, this rule is frequently violated by IRC - * servers itself - for example, NICKSERV messages require reply, and - * are NOTICEs. - * - * \param origin the person, who generates the message. - * \param params[0] mandatory, contains the target nick name. - * \param params[1] optional, contains the message text - */ - irc_event_callback_t event_notice; - - /*! - * The "channel_notice" event is triggered upon receipt of a NOTICE - * message which means that someone has sent the client a public - * notice. According to RFC 1459, the only difference between NOTICE - * and PRIVMSG is that you should NEVER automatically reply to NOTICE - * messages. Unfortunately, this rule is frequently violated by IRC - * servers itself - for example, NICKSERV messages require reply, and - * are NOTICEs. - * - * \param origin the person, who generates the message. - * \param params[0] mandatory, contains the channel name. - * \param params[1] optional, contains the message text - */ - irc_event_callback_t event_channel_notice; - - /*! - * The "server_notice" event is triggered upon receipt of a NOTICE - * message which means that the server has sent the client a notice. - * This notice is not necessarily addressed to the client's nick - * (for example, AUTH notices, sent before the client's nick is known). - * According to RFC 1459, the only difference between NOTICE - * and PRIVMSG is that you should NEVER automatically reply to NOTICE - * messages. Unfortunately, this rule is frequently violated by IRC - * servers itself - for example, NICKSERV messages require reply, and - * are NOTICEs. - * - * \param origin the person, who generates the message. - * \param params optional, contains who knows what. - */ - irc_event_callback_t event_server_notice; - - /*! - * The "invite" event is triggered upon receipt of an INVITE message, - * which means that someone is permitting the client's entry into a +i - * channel. - * - * \param origin the person, who INVITEs you. - * \param params[0] mandatory, contains your nick. - * \param params[1] mandatory, contains the channel name you're invited into. - * - * \sa irc_cmd_invite irc_cmd_chanmode_invite - */ - irc_event_callback_t event_invite; - - /*! - * The "ctcp" event is triggered when the client receives the CTCP - * request. By default, the built-in CTCP request handler is used. The - * build-in handler automatically replies on most CTCP messages, so you - * will rarely need to override it. - * - * \param origin the person, who generates the message. - * \param params[0] mandatory, the complete CTCP message, including its - * arguments. - * - * Mirc generates PING, FINGER, VERSION, TIME and ACTION messages, - * check the source code of \c libirc_event_ctcp_internal function to - * see how to write your own CTCP request handler. Also you may find - * useful this question in FAQ: \ref faq4 - */ - irc_event_callback_t event_ctcp_req; - - /*! - * The "ctcp" event is triggered when the client receives the CTCP reply. - * - * \param origin the person, who generates the message. - * \param params[0] mandatory, the CTCP message itself with its arguments. - */ - irc_event_callback_t event_ctcp_rep; - - /*! - * The "action" event is triggered when the client receives the CTCP - * ACTION message. These messages usually looks like:\n - * \code - * [23:32:55] * Tim gonna sleep. - * \endcode - * - * \param origin the person, who generates the message. - * \param params[0] mandatory, the ACTION message. - */ - irc_event_callback_t event_ctcp_action; - - /*! - * The "unknown" event is triggered upon receipt of any number of - * unclassifiable miscellaneous messages, which aren't handled by the - * library. - */ - irc_event_callback_t event_unknown; - - /*! - * The "numeric" event is triggered upon receipt of any numeric response - * from the server. There is a lot of such responses, see the full list - * here: \ref rfcnumbers. - * - * See the params in ::irc_eventcode_callback_t specification. - */ - irc_eventcode_callback_t event_numeric; - - /*! - * The "dcc chat" event is triggered when someone requests a DCC CHAT from - * you. - * - * See the params in ::irc_event_dcc_chat_t specification. - */ - irc_event_dcc_chat_t event_dcc_chat_req; - - /*! - * The "dcc send" event is triggered when someone wants to send a file - * to you via DCC SEND request. - * - * See the params in ::irc_event_dcc_send_t specification. - */ - irc_event_dcc_send_t event_dcc_send_req; - - -} irc_callbacks_t; - - -#endif /* INCLUDE_IRC_EVENTS_H */ diff --git a/libircclient/include/libirc_options.h b/libircclient/include/libirc_options.h deleted file mode 100644 index 89fa572..0000000 --- a/libircclient/include/libirc_options.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) 2004-2012 George Yunaev gyunaev@ulduzsoft.com - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 3 of the License, or (at your - * option) any later version. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public - * License for more details. - */ - -#ifndef INCLUDE_IRC_OPTIONS_H -#define INCLUDE_IRC_OPTIONS_H - -#ifndef IN_INCLUDE_LIBIRC_H - #error This file should not be included directly, include just libircclient.h -#endif - -/*! - * enables additional debug output - * \ingroup options - */ -#define LIBIRC_OPTION_DEBUG (1 << 1) - -/*! \brief allows to strip origins automatically. - * - * For every IRC server event, the event origin is sent in standard form: - * nick!host\@ircserver, i.e. like tim!home\@irc.freenet.org. Such origins - * can not be used in IRC commands, and need to be stripped (i.e. host and - * server part should be cut off) before using. This can be done either - * explicitly, by calling irc_target_get_nick(), or implicitly for all the - * events - by setting this option with irc_option_set(). - * \ingroup options - */ -#define LIBIRC_OPTION_STRIPNICKS (1 << 2) - - -/*! \brief Disables the certificate verification for SSL connections - * - * By default the SSL connection authenticy is ensured by verifying that the certificate - * presented by the server is signed by a known trusted certificate authority. Since those - * typically cost money, some IRC servers use the self-signed certificates. They provide the - * benefits of the SSL connection but since they are not signed by the Certificate Authority, - * their authencity cannot be verified. This option, if set, disables the certificate - * verification - the library will accept any certificate presented by the server. - * - * This option must be set before the irc_connect function is called. - * \ingroup options - */ -#define LIBIRC_OPTION_SSL_NO_VERIFY (1 << 3) - -/*! \brief Disables automatic response to PING messages. - * - * The library will still generate events for PING messages, if an event handler - * is provided. - * \ingroup options - */ -#define LIBIRC_OPTION_IGNORE_PING (1 << 4) - - -#endif /* INCLUDE_IRC_OPTIONS_H */ diff --git a/libircclient/include/libirc_rfcnumeric.h b/libircclient/include/libirc_rfcnumeric.h deleted file mode 100644 index 02c1337..0000000 --- a/libircclient/include/libirc_rfcnumeric.h +++ /dev/null @@ -1,1255 +0,0 @@ -/* - * Copyright (C) 2004-2012 George Yunaev gyunaev@ulduzsoft.com - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 3 of the License, or (at your - * option) any later version. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public - * License for more details. - */ - -/*! - * \file libirc_rfcnumeric.h - * \author Georgy Yunaev - * \version 1.0 - * \date 09.2004 - * \brief This file defines RFC numeric reply codes, which should be used in - * ::event_numeric callback. Every code also has a comment regarding its - * arguments. - */ - -#ifndef INCLUDE_IRC_RFCNUMERIC_H -#define INCLUDE_IRC_RFCNUMERIC_H - - -/*! \brief 001 Welcome to the Internet Relay Network - \!\\@\ - * - * The server sends replies 001 to 004 to a user upon successful registration. - * - * \ingroup rfcnumbers - */ -#define LIBIRC_RFC_RPL_WELCOME 001 - - -/*! \brief 002 Your host is \, running version \ - * - * The server sends replies 001 to 004 to a user upon successful registration. - * - * \ingroup rfcnumbers - */ -#define LIBIRC_RFC_RPL_YOURHOST 002 - - -/*! \brief 003 This server was created \ - * - * The server sends replies 001 to 004 to a user upon successful registration. - * - * \ingroup rfcnumbers - */ -#define LIBIRC_RFC_RPL_CREATED 003 - - -/*! \brief 004 \ \ \ - \ - * - * The server sends replies 001 to 004 to a user upon successful registration. - * - * \ingroup rfcnumbers - */ -#define LIBIRC_RFC_RPL_MYINFO 004 - - -/*! \brief 005 Try server \, port \ - * - * Sent by the server to a user to suggest an alternative server. This is often used when the connection is refused because the server is already full. - * - * \ingroup rfcnumbers - */ -#define LIBIRC_RFC_RPL_BOUNCE 005 - - -/*! \brief 302 :*1\ *( - * - * No description available in RFC - * - * \ingroup rfcnumbers - */ -#define LIBIRC_RFC_RPL_USERHOST 302 - - -/*! \brief 303 :*1\ *( - * - * No description available in RFC - * - * \ingroup rfcnumbers - */ -#define LIBIRC_RFC_RPL_ISON 303 - - -/*! \brief 301 \ :\ - * - * No description available in RFC - * - * \ingroup rfcnumbers - */ -#define LIBIRC_RFC_RPL_AWAY 301 - - -/*! \brief 305 :You are no longer marked as being away - * - * No description available in RFC - * - * \ingroup rfcnumbers - */ -#define LIBIRC_RFC_RPL_UNAWAY 305 - - -/*! \brief 306 :You have been marked as being away - * - * These replies are used with the AWAY command (if allowed). RPL_AWAY is sent to any client sending a PRIVMSG to a client which is away. RPL_AWAY is only sent by the server to which the client is connected. Replies RPL_UNAWAY and RPL_NOWAWAY are sent when the client removes and sets an AWAY message. - * - * \ingroup rfcnumbers - */ -#define LIBIRC_RFC_RPL_NOWAWAY 306 - - -/*! \brief 311 \ \ \ * :\ - * - * No description available in RFC - * - * \ingroup rfcnumbers - */ -#define LIBIRC_RFC_RPL_WHOISUSER 311 - - -/*! \brief 312 \ \ :\ - * - * No description available in RFC - * - * \ingroup rfcnumbers - */ -#define LIBIRC_RFC_RPL_WHOISSERVER 312 - - -/*! \brief 313 \ :is an IRC operator - * - * No description available in RFC - * - * \ingroup rfcnumbers - */ -#define LIBIRC_RFC_RPL_WHOISOPERATOR 313 - - -/*! \brief 317 \ \ :seconds idle - * - * No description available in RFC - * - * \ingroup rfcnumbers - */ -#define LIBIRC_RFC_RPL_WHOISIDLE 317 - - -/*! \brief 318 \ :End of WHOIS list - * - * No description available in RFC - * - * \ingroup rfcnumbers - */ -#define LIBIRC_RFC_RPL_ENDOFWHOIS 318 - - -/*! \brief 319 " :*( ( "\@" / "+" ) \ " " )" - * - * No description available in RFC - * - * \ingroup rfcnumbers - */ -#define LIBIRC_RFC_RPL_WHOISCHANNELS 319 - - -/*! \brief 314 \ \ \ * :\ - * - * No description available in RFC - * - * \ingroup rfcnumbers - */ -#define LIBIRC_RFC_RPL_WHOWASUSER 314 - - -/*! \brief 369 \ :End of WHOWAS - * - * When replying to a WHOWAS message, a server MUST use the replies RPL_WHOWASUSER, RPL_WHOISSERVER or ERR_WASNOSUCHNICK for each nickname in the presented list. At the end of all reply batches, there MUST be RPL_ENDOFWHOWAS (even if there was only one reply and it was an error). - * - * \ingroup rfcnumbers - */ -#define LIBIRC_RFC_RPL_ENDOFWHOWAS 369 - - -/*! \brief 322 \ \<# visible\> :\ - * - * No description available in RFC - * - * \ingroup rfcnumbers - */ -#define LIBIRC_RFC_RPL_LIST 322 - - -/*! \brief 323 :End of LIST - * - * Replies RPL_LIST, RPL_LISTEND mark the actual replies with data and end of the server's response to a LIST command. If there are no channels available to return, only the end reply MUST be sent. - * - * \ingroup rfcnumbers - */ -#define LIBIRC_RFC_RPL_LISTEND 323 - - -/*! \brief 325 \ \ - * - * No description available in RFC - * - * \ingroup rfcnumbers - */ -#define LIBIRC_RFC_RPL_UNIQOPIS 325 - - -/*! \brief 324 \ \ \ - * - * No description available in RFC - * - * \ingroup rfcnumbers - */ -#define LIBIRC_RFC_RPL_CHANNELMODEIS 324 - - -/*! \brief 331 \ :No topic is set - * - * No description available in RFC - * - * \ingroup rfcnumbers - */ -#define LIBIRC_RFC_RPL_NOTOPIC 331 - - -/*! \brief 332 \ :\ - * - * When sending a TOPIC message to determine the channel topic, one of two replies is sent. If the topic is set, RPL_TOPIC is sent back else RPL_NOTOPIC. - * - * \ingroup rfcnumbers - */ -#define LIBIRC_RFC_RPL_TOPIC 332 - - -/*! \brief 341 \ \ - * - * Returned by the server to indicate that the attempted INVITE message was successful and is being passed onto the end client. - * - * \ingroup rfcnumbers - */ -#define LIBIRC_RFC_RPL_INVITING 341 - - -/*! \brief 342 \ :Summoning user to IRC - * - * Returned by a server answering a SUMMON message to indicate that it is summoning that user. - * - * \ingroup rfcnumbers - */ -#define LIBIRC_RFC_RPL_SUMMONING 342 - - -/*! \brief 346 \ \ - * - * No description available in RFC - * - * \ingroup rfcnumbers - */ -#define LIBIRC_RFC_RPL_INVITELIST 346 - - -/*! \brief 347 \ :End of channel invite list - * - * When listing the 'invitations masks' for a given channel, a server is required to send the list back using the RPL_INVITELIST and RPL_ENDOFINVITELIST messages. A separate RPL_INVITELIST is sent for each active mask. After the masks have been listed (or if none present) a RPL_ENDOFINVITELIST MUST be sent. - * - * \ingroup rfcnumbers - */ -#define LIBIRC_RFC_RPL_ENDOFINVITELIST 347 - - -/*! \brief 348 \ \ - * - * No description available in RFC - * - * \ingroup rfcnumbers - */ -#define LIBIRC_RFC_RPL_EXCEPTLIST 348 - - -/*! \brief 349 \ :End of channel exception list - * - * When listing the 'exception masks' for a given channel, a server is required to send the list back using the RPL_EXCEPTLIST and RPL_ENDOFEXCEPTLIST messages. A separate RPL_EXCEPTLIST is sent for each active mask. After the masks have been listed (or if none present) a RPL_ENDOFEXCEPTLIST MUST be sent. - * - * \ingroup rfcnumbers - */ -#define LIBIRC_RFC_RPL_ENDOFEXCEPTLIST 349 - - -/*! \brief 351 \.\ \ :\ - * - * Reply by the server showing its version details. The \ is the version of the software being used (including any patchlevel revisions) and the \ is used to indicate if the server is running in "debug mode". The "comments" field may contain any comments about the version or further version details. - * - * \ingroup rfcnumbers - */ -#define LIBIRC_RFC_RPL_VERSION 351 - - -/*! \brief 352 \ \ \ \ \ - ( "H - * - * No description available in RFC - * - * \ingroup rfcnumbers - */ -#define LIBIRC_RFC_RPL_WHOREPLY 352 - - -/*! \brief 315 \ :End of WHO list - * - * The RPL_WHOREPLY and RPL_ENDOFWHO pair are used to answer a WHO message. The RPL_WHOREPLY is only sent if there is an appropriate match to the WHO query. If there is a list of parameters supplied with a WHO message, a RPL_ENDOFWHO MUST be sent after processing each list item with \ being the item. - * - * \ingroup rfcnumbers - */ -#define LIBIRC_RFC_RPL_ENDOFWHO 315 - - -/*! \brief 353 ( "= - * - * No description available in RFC - * - * \ingroup rfcnumbers - */ -#define LIBIRC_RFC_RPL_NAMREPLY 353 - - -/*! \brief 366 \ :End of NAMES list - * - * To reply to a NAMES message, a reply pair consisting of RPL_NAMREPLY and RPL_ENDOFNAMES is sent by the server back to the client. If there is no channel found as in the query, then only RPL_ENDOFNAMES is returned. The exception to this is when a NAMES message is sent with no parameters and all visible channels and contents are sent back in a series of RPL_NAMEREPLY messages with a RPL_ENDOFNAMES to mark the end. - * - * \ingroup rfcnumbers - */ -#define LIBIRC_RFC_RPL_ENDOFNAMES 366 - - -/*! \brief 364 \ \ :\ \ - * - * No description available in RFC - * - * \ingroup rfcnumbers - */ -#define LIBIRC_RFC_RPL_LINKS 364 - - -/*! \brief 365 \ :End of LINKS list - * - * In replying to the LINKS message, a server MUST send replies back using the RPL_LINKS numeric and mark the end of the list using an RPL_ENDOFLINKS reply. - * - * \ingroup rfcnumbers - */ -#define LIBIRC_RFC_RPL_ENDOFLINKS 365 - - -/*! \brief 367 \ \ - * - * No description available in RFC - * - * \ingroup rfcnumbers - */ -#define LIBIRC_RFC_RPL_BANLIST 367 - - -/*! \brief 368 \ :End of channel ban list - * - * When listing the active 'bans' for a given channel, a server is required to send the list back using the RPL_BANLIST and RPL_ENDOFBANLIST messages. A separate RPL_BANLIST is sent for each active banmask. After the banmasks have been listed (or if none present) a RPL_ENDOFBANLIST MUST be sent. - * - * \ingroup rfcnumbers - */ -#define LIBIRC_RFC_RPL_ENDOFBANLIST 368 - - -/*! \brief 371 :\ - * - * No description available in RFC - * - * \ingroup rfcnumbers - */ -#define LIBIRC_RFC_RPL_INFO 371 - - -/*! \brief 374 :End of INFO list - * - * A server responding to an INFO message is required to send all its 'info' in a series of RPL_INFO messages with a RPL_ENDOFINFO reply to indicate the end of the replies. - * - * \ingroup rfcnumbers - */ -#define LIBIRC_RFC_RPL_ENDOFINFO 374 - - -/*! \brief 375 :- \ Message of the day - - * - * No description available in RFC - * - * \ingroup rfcnumbers - */ -#define LIBIRC_RFC_RPL_MOTDSTART 375 - - -/*! \brief 372 :- \ - * - * No description available in RFC - * - * \ingroup rfcnumbers - */ -#define LIBIRC_RFC_RPL_MOTD 372 - - -/*! \brief 376 :End of MOTD command - * - * When responding to the MOTD message and the MOTD file is found, the file is displayed line by line, with each line no longer than 80 characters, using RPL_MOTD format replies. These MUST be surrounded by a RPL_MOTDSTART (before the RPL_MOTDs) and an RPL_ENDOFMOTD (after). - * - * \ingroup rfcnumbers - */ -#define LIBIRC_RFC_RPL_ENDOFMOTD 376 - - -/*! \brief 381 :You are now an IRC operator - * - * RPL_YOUREOPER is sent back to a client which has just successfully issued an OPER message and gained operator status. - * - * \ingroup rfcnumbers - */ -#define LIBIRC_RFC_RPL_YOUREOPER 381 - - -/*! \brief 382 \ :Rehashing - * - * If the REHASH option is used and an operator sends a REHASH message, an RPL_REHASHING is sent back to the operator. - * - * \ingroup rfcnumbers - */ -#define LIBIRC_RFC_RPL_REHASHING 382 - - -/*! \brief 383 You are service \ - * - * Sent by the server to a service upon successful registration. - * - * \ingroup rfcnumbers - */ -#define LIBIRC_RFC_RPL_YOURESERVICE 383 - - -/*! \brief 391 \ :\ - * - * When replying to the TIME message, a server MUST send the reply using the RPL_TIME format above. The string showing the time need only contain the correct day and time there. There is no further requirement for the time string. - * - * \ingroup rfcnumbers - */ -#define LIBIRC_RFC_RPL_TIME 391 - - -/*! \brief 392 :UserID Terminal Host - * - * No description available in RFC - * - * \ingroup rfcnumbers - */ -#define LIBIRC_RFC_RPL_USERSSTART 392 - - -/*! \brief 393 :\ \ \ - * - * No description available in RFC - * - * \ingroup rfcnumbers - */ -#define LIBIRC_RFC_RPL_USERS 393 - - -/*! \brief 394 :End of users - * - * No description available in RFC - * - * \ingroup rfcnumbers - */ -#define LIBIRC_RFC_RPL_ENDOFUSERS 394 - - -/*! \brief 395 :Nobody logged in - * - * If the USERS message is handled by a server, the replies RPL_USERSTART, RPL_USERS, RPL_ENDOFUSERS and RPL_NOUSERS are used. RPL_USERSSTART MUST be sent first, following by either a sequence of RPL_USERS or a single RPL_NOUSER. Following this is RPL_ENDOFUSERS. - * - * \ingroup rfcnumbers - */ -#define LIBIRC_RFC_RPL_NOUSERS 395 - - -/*! \brief 200 Link \ \ - \ V\ - \ \ - \ - * - * No description available in RFC - * - * \ingroup rfcnumbers - */ -#define LIBIRC_RFC_RPL_TRACELINK 200 - - -/*! \brief 201 Try. \ \ - * - * No description available in RFC - * - * \ingroup rfcnumbers - */ -#define LIBIRC_RFC_RPL_TRACECONNECTING 201 - - -/*! \brief 202 H.S. \ \ - * - * No description available in RFC - * - * \ingroup rfcnumbers - */ -#define LIBIRC_RFC_RPL_TRACEHANDSHAKE 202 - - -/*! \brief 203 ???? \ [\] - * - * No description available in RFC - * - * \ingroup rfcnumbers - */ -#define LIBIRC_RFC_RPL_TRACEUNKNOWN 203 - - -/*! \brief 204 Oper \ \ - * - * No description available in RFC - * - * \ingroup rfcnumbers - */ -#define LIBIRC_RFC_RPL_TRACEOPERATOR 204 - - -/*! \brief 205 User \ \ - * - * No description available in RFC - * - * \ingroup rfcnumbers - */ -#define LIBIRC_RFC_RPL_TRACEUSER 205 - - -/*! \brief 206 Serv \ \S \C \ - \\@\ V\ - * - * No description available in RFC - * - * \ingroup rfcnumbers - */ -#define LIBIRC_RFC_RPL_TRACESERVER 206 - - -/*! \brief 207 Service \ \ \ \ - * - * No description available in RFC - * - * \ingroup rfcnumbers - */ -#define LIBIRC_RFC_RPL_TRACESERVICE 207 - - -/*! \brief 208 \ 0 \ - * - * No description available in RFC - * - * \ingroup rfcnumbers - */ -#define LIBIRC_RFC_RPL_TRACENEWTYPE 208 - - -/*! \brief 209 Class \ \ - * - * No description available in RFC - * - * \ingroup rfcnumbers - */ -#define LIBIRC_RFC_RPL_TRACECLASS 209 - - -/*! \brief 261 File \ \ - * - * No description available in RFC - * - * \ingroup rfcnumbers - */ -#define LIBIRC_RFC_RPL_TRACELOG 261 - - -/*! \brief 262 \ \ :End of TRACE - * - * The RPL_TRACE* are all returned by the server in response to the TRACE message. How many are returned is dependent on the TRACE message and whether it was sent by an operator or not. There is no predefined order for which occurs first. Replies RPL_TRACEUNKNOWN, RPL_TRACECONNECTING and RPL_TRACEHANDSHAKE are all used for connections which have not been fully established and are either unknown, still attempting to connect or in the process of completing the 'server handshake'. RPL_TRACELINK is sent by any server which handles a TRACE message and has to pass it on to another server. The list of RPL_TRACELINKs sent in response to a TRACE command traversing the IRC network should reflect the actual connectivity of the servers themselves along that path. RPL_TRACENEWTYPE is to be used for any connection which does not fit in the other categories but is being displayed anyway. RPL_TRACEEND is sent to indicate the end of the list. - * - * \ingroup rfcnumbers - */ -#define LIBIRC_RFC_RPL_TRACEEND 262 - - -/*! \brief 211 \ \ \ - \ \ - \ \