Rewrite some IRCClientChannel functionality to rely less on libircclient’s implementation of IRC commands
This commit is contained in:
parent
3bb861b44d
commit
49fd91b2c7
@ -27,6 +27,8 @@
|
||||
* for a given session when the client joins an IRC channel.
|
||||
*/
|
||||
|
||||
@class IRCClientSession;
|
||||
|
||||
/**********************************************/
|
||||
#pragma mark IRCClientChannel class declaration
|
||||
/**********************************************/
|
||||
@ -40,6 +42,9 @@
|
||||
/** Delegate to send events to */
|
||||
@property (assign) id <IRCClientChannelDelegate> delegate;
|
||||
|
||||
/** Associated session */
|
||||
@property (readonly) IRCClientSession *session;
|
||||
|
||||
/** Name of the channel */
|
||||
@property (readonly) NSData *name;
|
||||
|
||||
@ -50,7 +55,7 @@
|
||||
*
|
||||
* You can (attempt to) set the topic by using setChannelTopic:, not by
|
||||
* changing this property (which is readonly). If the connected user has the
|
||||
* privileges to set the channel topic, the channel's delegate will receive a
|
||||
* privileges to set the channel topic, the channel’s delegate will receive a
|
||||
* topicSet:by: message (and the topic property of the channel object will be
|
||||
* updated automatically).
|
||||
*/
|
||||
@ -66,6 +71,12 @@
|
||||
/** Stores arbitrary user info. */
|
||||
@property (strong) NSDictionary *userInfo;
|
||||
|
||||
/********************************************/
|
||||
#pragma mark - Initializers & factory methods
|
||||
/********************************************/
|
||||
|
||||
+(instancetype) channel;
|
||||
|
||||
/**************************/
|
||||
#pragma mark - IRC commands
|
||||
/**************************/
|
||||
@ -86,7 +97,7 @@
|
||||
*
|
||||
* @param aTopic the topic the client wishes to set for the channel.
|
||||
*/
|
||||
- (void)setChannelTopic:(NSData *)newTopic;
|
||||
-(int) setChannelTopic:(NSData *)newTopic;
|
||||
|
||||
/** Sets the mode of the channel.
|
||||
*
|
||||
@ -95,7 +106,8 @@
|
||||
*
|
||||
* @param mode the mode to set the channel to
|
||||
*/
|
||||
- (int)setMode:(NSData *)mode params:(NSData *)params;
|
||||
-(int) setMode:(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.
|
||||
@ -121,7 +133,8 @@
|
||||
* @param nick the IRC client to kick from the channel.
|
||||
* @param reason the message to give to the channel and the IRC client for the kick.
|
||||
*/
|
||||
- (int)kick:(NSData *)nick reason:(NSData *)reason;
|
||||
-(int) kick:(NSData *)nick
|
||||
reason:(NSData *)reason;
|
||||
|
||||
/** Sends a CTCP request to the channel.
|
||||
*
|
||||
|
||||
@ -25,17 +25,14 @@
|
||||
#pragma mark IRCClientChannel class extension
|
||||
/********************************************/
|
||||
|
||||
@interface IRCClientChannel()
|
||||
{
|
||||
@interface IRCClientChannel() {
|
||||
irc_session_t *_irc_session;
|
||||
|
||||
// TODO: actually keep track of nicks! Use RPL_NAMREPLY and so on...
|
||||
// (see refreshNames...)
|
||||
NSMutableArray *_nicks;
|
||||
}
|
||||
|
||||
@property (readwrite) NSData *topic;
|
||||
@property (readwrite) NSData *modes;
|
||||
@property (readwrite) NSMutableArray *nicks;
|
||||
|
||||
@end
|
||||
|
||||
/***************************************************/
|
||||
@ -44,36 +41,42 @@
|
||||
|
||||
@implementation IRCClientChannel
|
||||
|
||||
/******************************/
|
||||
#pragma mark - Custom accessors
|
||||
/******************************/
|
||||
/************************/
|
||||
#pragma mark - Properties
|
||||
/************************/
|
||||
|
||||
-(NSArray *)nicks
|
||||
{
|
||||
NSArray* nicksCopy = [_nicks copy];
|
||||
return nicksCopy;
|
||||
-(NSArray *) nicks {
|
||||
return [_nicks copy];
|
||||
}
|
||||
|
||||
-(void)setNicks:(NSArray *)nicks
|
||||
{
|
||||
_nicks = [nicks mutableCopy];
|
||||
-(IRCClientSession *) session {
|
||||
return (__bridge IRCClientSession *) irc_get_ctx(_irc_session);
|
||||
}
|
||||
|
||||
/********************************************/
|
||||
#pragma mark - Initializers & factory methods
|
||||
/********************************************/
|
||||
|
||||
+(instancetype) channel {
|
||||
return [self new];
|
||||
}
|
||||
|
||||
/**************************/
|
||||
#pragma mark - Initializers
|
||||
/**************************/
|
||||
|
||||
-(instancetype)initWithName:(NSData *)name andIRCSession:(irc_session_t *)irc_session
|
||||
{
|
||||
if ((self = [super init]))
|
||||
{
|
||||
-(instancetype) initWithName:(NSData *)name
|
||||
andIRCSession:(irc_session_t *)irc_session {
|
||||
self = [super init];
|
||||
if (!self) return nil;
|
||||
|
||||
_irc_session = irc_session;
|
||||
|
||||
_name = name;
|
||||
_encoding = NSUTF8StringEncoding;
|
||||
_topic = [NSData dataWithBlankCString];
|
||||
_modes = [NSData dataWithBlankCString];
|
||||
}
|
||||
_nicks = [NSMutableArray array];
|
||||
|
||||
return self;
|
||||
}
|
||||
@ -82,110 +85,202 @@
|
||||
#pragma mark - IRC commands
|
||||
/**************************/
|
||||
|
||||
- (int)part
|
||||
{
|
||||
return irc_cmd_part(_irc_session, _name.SA_terminatedCString);
|
||||
-(int) part {
|
||||
return irc_send_raw(_irc_session,
|
||||
"PART %s",
|
||||
_name.SA_terminatedCString);
|
||||
}
|
||||
|
||||
- (int)invite:(NSData *)nick
|
||||
{
|
||||
return irc_cmd_invite(_irc_session, nick.SA_terminatedCString, _name.SA_terminatedCString);
|
||||
-(int) invite:(NSData *)nick {
|
||||
if (!nick || nick.length == 0)
|
||||
return LIBIRC_ERR_STATE;
|
||||
|
||||
return irc_send_raw(_irc_session,
|
||||
"INVITE %s %s",
|
||||
nick.SA_terminatedCString,
|
||||
_name.SA_terminatedCString);
|
||||
}
|
||||
|
||||
- (int)refreshNames
|
||||
{
|
||||
return irc_cmd_names(_irc_session, _name.SA_terminatedCString);
|
||||
-(int) refreshNames {
|
||||
return irc_send_raw(_irc_session,
|
||||
"NAMES %s",
|
||||
_name.SA_terminatedCString);
|
||||
}
|
||||
|
||||
- (void)setChannelTopic:(NSData *)newTopic
|
||||
{
|
||||
irc_cmd_topic(_irc_session, _name.SA_terminatedCString, newTopic.SA_terminatedCString);
|
||||
}
|
||||
|
||||
- (int)setMode:(NSData *)mode params:(NSData *)params
|
||||
{
|
||||
if(params != nil)
|
||||
{
|
||||
NSMutableData *fullModeString = (params != nil) ? [NSMutableData dataWithLength:mode.length + 1 + params.length] : [NSMutableData dataWithLength:mode.length];
|
||||
sprintf(fullModeString.mutableBytes, "%s %s", mode.bytes, params.bytes);
|
||||
|
||||
return irc_cmd_channel_mode(_irc_session, _name.SA_terminatedCString, fullModeString.SA_terminatedCString);
|
||||
}
|
||||
-(int) setChannelTopic:(NSData *)newTopic {
|
||||
if (newTopic)
|
||||
return irc_send_raw(_irc_session,
|
||||
"TOPIC %s :%s",
|
||||
_name.SA_terminatedCString,
|
||||
newTopic.SA_terminatedCString);
|
||||
else
|
||||
{
|
||||
return irc_cmd_channel_mode(_irc_session, _name.SA_terminatedCString, mode.SA_terminatedCString);
|
||||
return irc_send_raw(_irc_session,
|
||||
"TOPIC %s",
|
||||
_name.SA_terminatedCString);
|
||||
}
|
||||
|
||||
-(int) setMode:(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.SA_terminatedCString,
|
||||
params.SA_terminatedCString);
|
||||
|
||||
return irc_send_raw(_irc_session,
|
||||
"MODE %s %s",
|
||||
_name.SA_terminatedCString,
|
||||
fullModeString.SA_terminatedCString);
|
||||
} else {
|
||||
return irc_send_raw(_irc_session,
|
||||
"MODE %s",
|
||||
_name.SA_terminatedCString);
|
||||
}
|
||||
}
|
||||
|
||||
- (int)message:(NSData *)message
|
||||
{
|
||||
return irc_cmd_msg(_irc_session, _name.SA_terminatedCString, message.SA_terminatedCString);
|
||||
-(int) message:(NSData *)message {
|
||||
if (!message || message.length == 0)
|
||||
return LIBIRC_ERR_STATE;
|
||||
|
||||
return irc_send_raw(_irc_session,
|
||||
"PRIVMSG %s :%s",
|
||||
_name.SA_terminatedCString,
|
||||
irc_color_convert_to_mirc(message.SA_terminatedCString));
|
||||
}
|
||||
|
||||
- (int)action:(NSData *)action
|
||||
{
|
||||
return irc_cmd_me(_irc_session, _name.SA_terminatedCString, action.SA_terminatedCString);
|
||||
-(int) action:(NSData *)action {
|
||||
if (!action || action.length == 0)
|
||||
return LIBIRC_ERR_STATE;
|
||||
|
||||
return irc_send_raw(_irc_session,
|
||||
"PRIVMSG %s :\x01" "ACTION %s\x01",
|
||||
_name.SA_terminatedCString,
|
||||
irc_color_convert_to_mirc(action.SA_terminatedCString));
|
||||
}
|
||||
|
||||
- (int)notice:(NSData *)notice
|
||||
{
|
||||
return irc_cmd_notice(_irc_session, _name.SA_terminatedCString, notice.SA_terminatedCString);
|
||||
-(int) notice:(NSData *)notice {
|
||||
if (!notice || notice.length == 0)
|
||||
return LIBIRC_ERR_STATE;
|
||||
|
||||
return irc_send_raw(_irc_session,
|
||||
"NOTICE %s :%s",
|
||||
_name.SA_terminatedCString,
|
||||
notice.SA_terminatedCString);
|
||||
}
|
||||
|
||||
- (int)kick:(NSData *)nick reason:(NSData *)reason
|
||||
{
|
||||
return irc_cmd_kick(_irc_session, nick.SA_terminatedCString, _name.SA_terminatedCString, reason.SA_terminatedCString);
|
||||
-(int) kick:(NSData *)nick
|
||||
reason:(NSData *)reason {
|
||||
if (!nick || nick.length == 0)
|
||||
return LIBIRC_ERR_STATE;
|
||||
|
||||
if (reason)
|
||||
return irc_send_raw(_irc_session,
|
||||
"KICK %s %s :%s",
|
||||
_name.SA_terminatedCString,
|
||||
nick.SA_terminatedCString,
|
||||
reason.SA_terminatedCString);
|
||||
else
|
||||
return irc_send_raw(_irc_session,
|
||||
"KICK %s %s",
|
||||
_name.SA_terminatedCString,
|
||||
nick.SA_terminatedCString);
|
||||
}
|
||||
|
||||
- (int)ctcpRequest:(NSData *)request
|
||||
{
|
||||
return irc_cmd_ctcp_request(_irc_session, _name.SA_terminatedCString, request.SA_terminatedCString);
|
||||
-(int) ctcpRequest:(NSData *)request {
|
||||
if (!request || request.length == 0)
|
||||
return LIBIRC_ERR_STATE;
|
||||
|
||||
return irc_send_raw(_irc_session,
|
||||
"PRIVMSG %s :\x01%s\x01",
|
||||
_name.SA_terminatedCString,
|
||||
request.SA_terminatedCString);
|
||||
}
|
||||
|
||||
/****************************/
|
||||
#pragma mark - Event handlers
|
||||
/****************************/
|
||||
|
||||
- (void)userJoined:(NSData *)nick
|
||||
{
|
||||
[_delegate userJoined:nick channel:self];
|
||||
-(void) userJoined:(NSData *)nick {
|
||||
[_nicks addObject:nick];
|
||||
|
||||
[_delegate userJoined:nick
|
||||
channel:self];
|
||||
}
|
||||
|
||||
- (void)userParted:(NSData *)nick withReason:(NSData *)reason us:(BOOL)wasItUs
|
||||
{
|
||||
[_delegate userParted:nick channel:self withReason:reason us:wasItUs];
|
||||
-(void) userParted:(NSData *)nick
|
||||
withReason:(NSData *)reason
|
||||
us:(BOOL)wasItUs {
|
||||
if (!wasItUs)
|
||||
[_nicks removeObject:nick];
|
||||
// TODO: but what if it was us? the delegate handles it...? or do we do
|
||||
// something here?
|
||||
|
||||
[_delegate userParted:nick
|
||||
channel:self
|
||||
withReason:reason
|
||||
us:wasItUs];
|
||||
}
|
||||
|
||||
- (void)modeSet:(NSData *)mode withParams:(NSData *)params by:(NSData *)nick
|
||||
{
|
||||
[_delegate modeSet:mode forChannel:self withParams:params by:nick];
|
||||
-(void) modeSet:(NSData *)mode
|
||||
withParams:(NSData *)params
|
||||
by:(NSData *)nick {
|
||||
// TODO: actually update the mode based on this event ... figure out what
|
||||
// mode set event returns?
|
||||
// _modes =
|
||||
|
||||
[_delegate modeSet:mode
|
||||
forChannel:self
|
||||
withParams:params
|
||||
by:nick];
|
||||
}
|
||||
|
||||
- (void)topicSet:(NSData *)topic by:(NSData *)nick
|
||||
{
|
||||
-(void) topicSet:(NSData *)topic
|
||||
by:(NSData *)nick {
|
||||
_topic = topic;
|
||||
|
||||
[_delegate topicSet:topic forChannel:self by:nick];
|
||||
[_delegate topicSet:topic
|
||||
forChannel:self
|
||||
by:nick];
|
||||
}
|
||||
|
||||
- (void)userKicked:(NSData *)nick withReason:(NSData *)reason by:(NSData *)byNick us:(BOOL)wasItUs
|
||||
{
|
||||
[_delegate userKicked:nick fromChannel:self withReason:reason by:byNick us:wasItUs];
|
||||
-(void) userKicked:(NSData *)nick
|
||||
withReason:(NSData *)reason
|
||||
by:(NSData *)byNick
|
||||
us:(BOOL)wasItUs {
|
||||
if (!wasItUs)
|
||||
[_nicks removeObject:nick];
|
||||
// TODO: but what if it was us? the delegate handles it...? or do we do
|
||||
// something here?
|
||||
|
||||
[_delegate userKicked:nick
|
||||
fromChannel:self
|
||||
withReason:reason
|
||||
by:byNick
|
||||
us:wasItUs];
|
||||
}
|
||||
|
||||
- (void)messageSent:(NSData *)message byUser:(NSData *)nick
|
||||
{
|
||||
[_delegate messageSent:message byUser:nick onChannel:self];
|
||||
-(void) messageSent:(NSData *)message
|
||||
byUser:(NSData *)nick {
|
||||
[_delegate messageSent:message
|
||||
byUser:nick
|
||||
onChannel:self];
|
||||
}
|
||||
|
||||
- (void)noticeSent:(NSData *)notice byUser:(NSData *)nick
|
||||
{
|
||||
[_delegate noticeSent:notice byUser:nick onChannel:self];
|
||||
-(void) noticeSent:(NSData *)notice
|
||||
byUser:(NSData *)nick {
|
||||
[_delegate noticeSent:notice
|
||||
byUser:nick
|
||||
onChannel:self];
|
||||
}
|
||||
|
||||
- (void)actionPerformed:(NSData *)action byUser:(NSData *)nick
|
||||
{
|
||||
[_delegate actionPerformed:action byUser:nick onChannel:self];
|
||||
-(void) actionPerformed:(NSData *)action
|
||||
byUser:(NSData *)nick {
|
||||
[_delegate actionPerformed:action
|
||||
byUser:nick
|
||||
onChannel:self];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@ -41,7 +41,8 @@
|
||||
*
|
||||
* @param nick The nickname of the user that joined the channel.
|
||||
*/
|
||||
- (void)userJoined:(NSData *)nick channel:(IRCClientChannel *)sender;
|
||||
-(void) userJoined:(NSData *)nick
|
||||
channel:(IRCClientChannel *)session;
|
||||
|
||||
/** When an IRC client parts a channel you are connect to, you will see
|
||||
* an onPart event. You will also see this event when you part a channel.
|
||||
@ -50,7 +51,10 @@
|
||||
* @param reason (optional) The reason, if any, that the user gave for leaving.
|
||||
* @param wasItUs (required) Was it us who parted, or another user?
|
||||
*/
|
||||
- (void)userParted:(NSData *)nick channel:(IRCClientChannel *)sender withReason:(NSData *)reason us:(BOOL)wasItUs;
|
||||
-(void) userParted:(NSData *)nick
|
||||
channel:(IRCClientChannel *)session
|
||||
withReason:(NSData *)reason
|
||||
us:(BOOL)wasItUs;
|
||||
|
||||
/** Received when an IRC client changes the channel mode. What modes are available
|
||||
* for a given channel is an implementation detail for each server.
|
||||
@ -59,14 +63,19 @@
|
||||
* @param params any parameters with the mode (such as channel key).
|
||||
* @param nick the nickname of the IRC client that changed the mode.
|
||||
*/
|
||||
- (void)modeSet:(NSData *)mode forChannel:(IRCClientChannel *)sender withParams:(NSData *)params by:(NSData *)nick;
|
||||
-(void) modeSet:(NSData *)mode
|
||||
forChannel:(IRCClientChannel *)session
|
||||
withParams:(NSData *)params
|
||||
by:(NSData *)nick;
|
||||
|
||||
/** Received when the topic is changed for the channel.
|
||||
*
|
||||
* @param aTopic The new topic of the channel.
|
||||
* @param nick Nickname of the IRC client that changed the topic.
|
||||
*/
|
||||
- (void)topicSet:(NSData *)topic forChannel:(IRCClientChannel *)sender by:(NSData *)nick;
|
||||
-(void) topicSet:(NSData *)topic
|
||||
forChannel:(IRCClientChannel *)session
|
||||
by:(NSData *)nick;
|
||||
|
||||
/** Received when an IRC client is kicked from a channel.
|
||||
*
|
||||
@ -75,7 +84,11 @@
|
||||
* @param byNick nickname of the client that performed the kick command
|
||||
* @param wasItUs Was it us who got kicked, or another user?
|
||||
*/
|
||||
- (void)userKicked:(NSData *)nick fromChannel:(IRCClientChannel *)sender withReason:(NSData *)reason by:(NSData *)byNick us:(BOOL)wasItUs;
|
||||
-(void) userKicked:(NSData *)nick
|
||||
fromChannel:(IRCClientChannel *)session
|
||||
withReason:(NSData *)reason
|
||||
by:(NSData *)byNick
|
||||
us:(BOOL)wasItUs;
|
||||
|
||||
/** Received when an IRC client sends a public PRIVMSG to the channel. Note that the
|
||||
* user may not necessarily be required to be on the channel to send a message
|
||||
@ -84,7 +97,9 @@
|
||||
* @param message the message sent to the channel.
|
||||
* @param nick the nickname of the IRC client that sent the message.
|
||||
*/
|
||||
- (void)messageSent:(NSData *)message byUser:(NSData *)nick onChannel:(IRCClientChannel *)sender;
|
||||
-(void) messageSent:(NSData *)message
|
||||
byUser:(NSData *)nick
|
||||
onChannel:(IRCClientChannel *)session;
|
||||
|
||||
/** Received when an IRC client sends a public NOTICE to the channel. Note that
|
||||
* the user may not necessarily be required to be on the channel to send a notice to
|
||||
@ -94,13 +109,17 @@
|
||||
* @param notice the notice sent to the channel.
|
||||
* @param nick the nickname of the IRC client that sent the notice.
|
||||
*/
|
||||
- (void)noticeSent:(NSData *)notice byUser:(NSData *)nick onChannel:(IRCClientChannel *)sender;
|
||||
-(void) noticeSent:(NSData *)notice
|
||||
byUser:(NSData *)nick
|
||||
onChannel:(IRCClientChannel *)session;
|
||||
|
||||
/** Received when an IRC client sends a CTCP ACTION message to the channel.
|
||||
*
|
||||
* @param action the action message sent to the channel.
|
||||
* @param nick the nickname of the IRC client that sent the message.
|
||||
*/
|
||||
- (void)actionPerformed:(NSData *)action byUser:(NSData *)nick onChannel:(IRCClientChannel *)sender;
|
||||
-(void) actionPerformed:(NSData *)action
|
||||
byUser:(NSData *)nick
|
||||
onChannel:(IRCClientChannel *)session;
|
||||
|
||||
@end
|
||||
|
||||
@ -27,37 +27,49 @@
|
||||
/** initWithName:andIRCSession:
|
||||
*
|
||||
* Returns an initialised IRCClientChannel with a given channel name, associated
|
||||
* with the given irc_session_t object. You are not expected to initialise your
|
||||
* with the given irc_session_t 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;
|
||||
-(instancetype) initWithName:(NSData *)aName
|
||||
andIRCSession:(irc_session_t *)session;
|
||||
|
||||
/****************************/
|
||||
#pragma mark - Event handlers
|
||||
/****************************/
|
||||
|
||||
/* NOTE: These methods are not to be called by classes that use IRCClient;
|
||||
* they are for the framework's internal use only. Do not import this header
|
||||
* they are for the framework’s internal use only. Do not import this header
|
||||
* in files that make use of the IRCClientChannel class.
|
||||
*/
|
||||
|
||||
-(void) userJoined:(NSData *)nick;
|
||||
|
||||
- (void)userParted:(NSData *)nick withReason:(NSData *)reason us:(BOOL)wasItUs;
|
||||
-(void) userParted:(NSData *)nick
|
||||
withReason:(NSData *)reason
|
||||
us:(BOOL)wasItUs;
|
||||
|
||||
- (void)modeSet:(NSData *)mode withParams:(NSData *)params by:(NSData *)nick;
|
||||
-(void) modeSet:(NSData *)mode
|
||||
withParams:(NSData *)params
|
||||
by:(NSData *)nick;
|
||||
|
||||
- (void)topicSet:(NSData *)newTopic by:(NSData *)nick;
|
||||
-(void) topicSet:(NSData *)newTopic
|
||||
by:(NSData *)nick;
|
||||
|
||||
- (void)userKicked:(NSData *)nick withReason:(NSData *)reason by:(NSData *)byNick us:(BOOL)wasItUs;
|
||||
-(void) userKicked:(NSData *)nick
|
||||
withReason:(NSData *)reason
|
||||
by:(NSData *)byNick
|
||||
us:(BOOL)wasItUs;
|
||||
|
||||
- (void)messageSent:(NSData *)message byUser:(NSData *)nick;
|
||||
-(void) messageSent:(NSData *)message
|
||||
byUser:(NSData *)nick;
|
||||
|
||||
- (void)noticeSent:(NSData *)notice byUser:(NSData *)nick;
|
||||
-(void) noticeSent:(NSData *)notice
|
||||
byUser:(NSData *)nick;
|
||||
|
||||
- (void)actionPerformed:(NSData *)action byUser:(NSData *)nick;
|
||||
-(void) actionPerformed:(NSData *)action
|
||||
byUser:(NSData *)nick;
|
||||
|
||||
@end
|
||||
|
||||
Loading…
Reference in New Issue
Block a user