IRC client framework (wrapper around libircclient library).
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

IRCClientSession.m 31KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948
  1. /*
  2. * Modified IRCClient Copyright 2015 Said Achmiz (www.saidachmiz.net)
  3. *
  4. * Original IRCClient Copyright (C) 2009 Nathan Ollerenshaw chrome@stupendous.net
  5. *
  6. * This library is free software; you can redistribute it and/or modify it
  7. * under the terms of the GNU Lesser General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or (at your
  9. * option) any later version.
  10. *
  11. * This library is distributed in the hope that it will be useful, but WITHOUT
  12. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
  14. * License for more details.
  15. */
  16. #pragma mark Defines and includes
  17. #define IRCCLIENTVERSION "1.0"
  18. #import "IRCClientSession.h"
  19. #import "IRCClientChannel.h"
  20. #import "IRCClientChannel_Private.h"
  21. #include "string.h"
  22. #pragma mark - Callback function declarations
  23. static void onConnect(irc_session_t *session, const char *event, const char *origin, const char **params, unsigned int count);
  24. static void onNick(irc_session_t *session, const char *event, const char *origin, const char **params, unsigned int count);
  25. static void onQuit(irc_session_t *session, const char *event, const char *origin, const char **params, unsigned int count);
  26. static void onJoinChannel(irc_session_t *session, const char *event, const char *origin, const char **params, unsigned int count);
  27. static void onPartChannel(irc_session_t *session, const char *event, const char *origin, const char **params, unsigned int count);
  28. static void onMode(irc_session_t *session, const char *event, const char *origin, const char **params, unsigned int count);
  29. static void onUserMode(irc_session_t *session, const char *event, const char *origin, const char **params, unsigned int count);
  30. static void onTopic(irc_session_t *session, const char *event, const char *origin, const char **params, unsigned int count);
  31. static void onKick(irc_session_t *session, const char *event, const char *origin, const char **params, unsigned int count);
  32. static void onChannelPrvmsg(irc_session_t *session, const char *event, const char *origin, const char **params, unsigned int count);
  33. static void onPrivmsg(irc_session_t *session, const char *event, const char *origin, const char **params, unsigned int count);
  34. static void onNotice(irc_session_t *session, const char *event, const char *origin, const char **params, unsigned int count);
  35. static void onChannelNotice(irc_session_t *session, const char *event, const char *origin, const char **params, unsigned int count);
  36. static void onInvite(irc_session_t *session, const char *event, const char *origin, const char **params, unsigned int count);
  37. static void onCtcpRequest(irc_session_t *session, const char *event, const char *origin, const char **params, unsigned int count);
  38. static void onCtcpReply(irc_session_t *session, const char *event, const char *origin, const char **params, unsigned int count);
  39. static void onCtcpAction(irc_session_t *session, const char *event, const char *origin, const char **params, unsigned int count);
  40. static void onUnknownEvent(irc_session_t *session, const char *event, const char *origin, const char **params, unsigned int count);
  41. static void onNumericEvent(irc_session_t *session, unsigned int event, const char *origin, const char **params, unsigned int count);
  42. #pragma mark - IRCClientSession private category declaration
  43. @interface IRCClientSession()
  44. {
  45. irc_callbacks_t callbacks;
  46. irc_session_t *irc_session;
  47. NSThread *thread;
  48. NSString *version;
  49. NSString *server;
  50. NSUInteger port;
  51. NSData *password;
  52. NSString *nickname;
  53. NSString *username;
  54. NSString *realname;
  55. NSMutableDictionary *channels;
  56. NSStringEncoding encoding;
  57. }
  58. @property (nonatomic, retain) NSMutableDictionary *channels;
  59. @end
  60. #pragma mark - IRCClientSession class implementation
  61. @implementation IRCClientSession
  62. #pragma mark - Property synthesis
  63. @synthesize delegate;
  64. @synthesize sessionID;
  65. @synthesize version;
  66. @synthesize server;
  67. @synthesize port;
  68. @synthesize password;
  69. @synthesize nickname;
  70. @synthesize username;
  71. @synthesize realname;
  72. @synthesize encoding;
  73. #pragma mark - Custom accessors
  74. -(NSDictionary*)channels
  75. {
  76. NSDictionary* channelsCopy = [channels copy];
  77. return channelsCopy;
  78. }
  79. -(void)setChannels:(NSMutableDictionary *)newChannels
  80. {
  81. channels = newChannels;
  82. }
  83. - (bool)connected
  84. {
  85. return irc_is_connected(irc_session);
  86. }
  87. /************************************/
  88. #pragma mark - Class methods
  89. /************************************/
  90. -(instancetype)init
  91. {
  92. if ((self = [super init])) {
  93. callbacks.event_connect = onConnect;
  94. callbacks.event_nick = onNick;
  95. callbacks.event_quit = onQuit;
  96. callbacks.event_join = onJoinChannel;
  97. callbacks.event_part = onPartChannel;
  98. callbacks.event_mode = onMode;
  99. callbacks.event_umode = onUserMode;
  100. callbacks.event_topic = onTopic;
  101. callbacks.event_kick = onKick;
  102. callbacks.event_channel = onChannelPrvmsg;
  103. callbacks.event_privmsg = onPrivmsg;
  104. callbacks.event_notice = onNotice;
  105. callbacks.event_channel_notice = onChannelNotice;
  106. callbacks.event_invite = onInvite;
  107. callbacks.event_ctcp_req = onCtcpRequest;
  108. callbacks.event_ctcp_rep = onCtcpReply;
  109. callbacks.event_ctcp_action = onCtcpAction;
  110. callbacks.event_unknown = onUnknownEvent;
  111. callbacks.event_numeric = onNumericEvent;
  112. callbacks.event_dcc_chat_req = NULL;
  113. callbacks.event_dcc_send_req = NULL;
  114. irc_session = irc_create_session(&callbacks);
  115. if (!irc_session) {
  116. NSLog(@"Could not create irc_session.");
  117. return nil;
  118. }
  119. // Strip server info from nicks.
  120. // irc_option_set(irc_session, LIBIRC_OPTION_STRIPNICKS);
  121. irc_set_ctx(irc_session, (__bridge void *)(self));
  122. unsigned int high, low;
  123. irc_get_version (&high, &low);
  124. version = [NSString stringWithFormat:@"IRCClient Framework v%s (Nathan Ollerenshaw) - libirc v%d.%d (Georgy Yunaev)", IRCCLIENTVERSION, high, low];
  125. channels = [[NSMutableDictionary alloc] init];
  126. }
  127. return self;
  128. }
  129. -(void)dealloc
  130. {
  131. if (irc_is_connected(irc_session))
  132. NSLog(@"Warning: IRC Session is not disconnected on dealloc");
  133. irc_destroy_session(irc_session);
  134. }
  135. - (int)connect;
  136. {
  137. unsigned short sPort = port;
  138. return irc_connect(irc_session, server.UTF8String, sPort, (password.length > 0 ? password.bytes : NULL), nickname.UTF8String, username.UTF8String, realname.UTF8String);
  139. }
  140. - (void)disconnect
  141. {
  142. irc_disconnect(irc_session);
  143. }
  144. - (void)startThread
  145. {
  146. @autoreleasepool {
  147. irc_run(irc_session);
  148. }
  149. }
  150. - (void)run
  151. {
  152. if (thread) {
  153. NSLog(@"Thread already running!");
  154. return;
  155. }
  156. thread = [[NSThread alloc] initWithTarget:self selector:@selector(startThread) object:nil];
  157. [thread start];
  158. }
  159. /**************************/
  160. #pragma mark - IRC commands
  161. /**************************/
  162. - (int)sendRaw:(NSData *)message
  163. {
  164. return irc_send_raw(irc_session, message.bytes);
  165. }
  166. - (int)quit:(NSData *)reason
  167. {
  168. return irc_cmd_quit(irc_session, reason.bytes);
  169. }
  170. - (int)join:(NSData *)channel key:(NSData *)key
  171. {
  172. NSLog(@"Joining %@", channel);
  173. if (!key || !key.length > 0)
  174. return irc_cmd_join(irc_session, channel.bytes, NULL);
  175. return irc_cmd_join(irc_session, channel.bytes, key.bytes);
  176. }
  177. - (int)list:(NSData *)channel
  178. {
  179. return irc_cmd_list(irc_session, channel.bytes);
  180. }
  181. - (int)userMode:(NSString *)mode
  182. {
  183. return irc_cmd_user_mode(irc_session, mode.UTF8String);
  184. }
  185. - (int)nick:(NSString *)newnick
  186. {
  187. return irc_cmd_nick(irc_session, newnick.UTF8String);
  188. }
  189. - (int)whois:(NSString *)nick
  190. {
  191. return irc_cmd_whois(irc_session, nick.UTF8String);
  192. }
  193. - (int)message:(NSData *)message to:(NSString *)target
  194. {
  195. return irc_cmd_msg(irc_session, target.UTF8String, message.bytes);
  196. }
  197. - (int)action:(NSData *)action to:(NSString *)target
  198. {
  199. return irc_cmd_me(irc_session, target.UTF8String, action.bytes);
  200. }
  201. - (int)notice:(NSData *)notice to:(NSString *)target
  202. {
  203. return irc_cmd_notice(irc_session, target.UTF8String, notice.bytes);
  204. }
  205. - (int)ctcpRequest:(NSData *)request target:(NSString *)target
  206. {
  207. return irc_cmd_ctcp_request(irc_session, target.UTF8String, request.bytes);
  208. }
  209. - (int)ctcpReply:(NSData *)reply target:(NSString *)target
  210. {
  211. return irc_cmd_ctcp_reply(irc_session, target.UTF8String, reply.bytes);
  212. }
  213. /****************************/
  214. #pragma mark - Event handlers
  215. /****************************/
  216. - (void)connectionSucceeded
  217. {
  218. [delegate connectionSucceeded];
  219. }
  220. - (void)nickChangedFrom:(NSString *)oldNick to:(NSString *)newNick
  221. {
  222. if ([nickname isEqualToString:oldNick])
  223. {
  224. nickname = newNick;
  225. [delegate nickChangedFrom:oldNick to:newNick own:YES];
  226. }
  227. else
  228. {
  229. [delegate nickChangedFrom:oldNick to:newNick own:NO];
  230. }
  231. }
  232. - (void)userQuit:(NSString *)nick withReason:(NSData *)reason
  233. {
  234. NSString* reasonString;
  235. if(reason)
  236. {
  237. reasonString = [[NSString alloc] initWithData:reason encoding:encoding];
  238. }
  239. [delegate userQuit:nick withReason:reasonString];
  240. }
  241. - (void)userJoined:(NSString *)nick channel:(NSData *)channelName
  242. {
  243. NSString* nickOnly = getNickFromNickUserHost(nick);
  244. if ([nickname isEqualToString:nickOnly])
  245. {
  246. // We just joined a channel; allocate an IRCClientChannel object and send it
  247. // to the main thread.
  248. IRCClientChannel* newChannel = [[IRCClientChannel alloc] initWithName:channelName andIRCSession:irc_session];
  249. channels[channelName] = newChannel;
  250. [delegate joinedNewChannel:newChannel];
  251. }
  252. else
  253. {
  254. // Someone joined a channel we're on.
  255. IRCClientChannel* channel = channels[channelName];
  256. [channel userJoined:nick];
  257. }
  258. }
  259. - (void)userParted:(NSString *)nick channel:(NSData *)channelName withReason:(NSData *)reason
  260. {
  261. IRCClientChannel* channel = channels[channelName];
  262. NSString* nickOnly = getNickFromNickUserHost(nick);
  263. if ([nickname isEqualToString:nickOnly])
  264. {
  265. // We just left a channel; remove it from the channels dict.
  266. [channels removeObjectForKey:channelName];
  267. [channel userParted:nick withReason:reason us:YES];
  268. }
  269. else
  270. {
  271. [channel userParted:nick withReason:reason us:NO];
  272. }
  273. }
  274. - (void)modeSet:(NSString* )mode withParams:(NSString *)params forChannel:(NSData *)channelName by:(NSString *)nick
  275. {
  276. IRCClientChannel *channel = channels[channelName];
  277. [channel modeSet:mode withParams:params by:nick];
  278. }
  279. - (void)modeSet:(NSString *)mode by:(NSString *)nick
  280. {
  281. [delegate modeSet:mode by:nick];
  282. }
  283. - (void)topicSet:(NSData *)newTopic forChannel:(NSData *)channelName by:(NSString *)nick
  284. {
  285. IRCClientChannel *channel = channels[channelName];
  286. [channel topicSet:newTopic by:nick];
  287. }
  288. - (void)userKicked:(NSString *)nick fromChannel:(NSData *)channelName by:(NSString *)byNick withReason:(NSData *)reason
  289. {
  290. IRCClientChannel* channel = channels[channelName];
  291. if (nick == nil)
  292. {
  293. // we got kicked from a channel we're on
  294. [channels removeObjectForKey:channelName];
  295. [channel userKicked:nickname withReason:reason by:byNick us:YES];
  296. }
  297. else
  298. {
  299. // someone else got booted from a channel we're on
  300. [channel userKicked:nick withReason:reason by:byNick us:NO];
  301. }
  302. }
  303. - (void)messageSent:(NSData *)message toChannel:(NSData *)channelName byUser:(NSString *)nick
  304. {
  305. IRCClientChannel *channel = channels[channelName];
  306. [channel messageSent:message byUser:nick];
  307. }
  308. - (void)privateMessageReceived:(NSData *)message fromUser:(NSString *)nick
  309. {
  310. NSString* messageString = [[NSString alloc] initWithData:message encoding:encoding];
  311. [delegate privateMessageReceived:messageString fromUser:nick];
  312. }
  313. - (void)noticeSent:(NSData *)notice toChannel:(NSData *)channelName byUser:(NSString *)nick
  314. {
  315. IRCClientChannel *channel = channels[channelName];
  316. [channel noticeSent:notice byUser:nick];
  317. }
  318. - (void)privateNoticeReceived:(NSData *)notice fromUser:(NSString *)nick
  319. {
  320. NSString* noticeString = [[NSString alloc] initWithData:notice encoding:encoding];
  321. [delegate privateNoticeReceived:noticeString fromUser:nick];
  322. }
  323. - (void)invitedToChannel:(NSData *)channelName by:(NSString *)nick
  324. {
  325. [delegate invitedToChannel:channelName by:nick];
  326. }
  327. - (void)CTCPRequestReceived:(NSData *)request fromUser:(NSString *)nick
  328. {
  329. const char* the_nick = getNickFromNickUserHost(nick).UTF8String;
  330. const char* the_request = request.bytes;
  331. if (strstr(the_request, "PING") == the_request)
  332. {
  333. irc_cmd_ctcp_reply(irc_session, the_nick, the_request);
  334. }
  335. else if (!strcmp (the_request, "VERSION"))
  336. {
  337. irc_cmd_ctcp_reply (irc_session, the_nick, [NSString stringWithFormat:@"VERSION %@", version].UTF8String);
  338. }
  339. else if (!strcmp (the_request, "FINGER"))
  340. {
  341. irc_cmd_ctcp_reply (irc_session, the_nick, [NSString stringWithFormat:@"FINGER %@ (%@) Idle 0 seconds", username, realname].UTF8String);
  342. }
  343. else if (!strcmp (the_request, "TIME"))
  344. {
  345. irc_cmd_ctcp_reply(irc_session, the_nick, [[NSDate dateWithTimeIntervalSinceNow:0] descriptionWithCalendarFormat:@"TIME %a %b %e %H:%M:%S %Z %Y" timeZone:nil locale:[[NSUserDefaults standardUserDefaults] dictionaryRepresentation]].UTF8String);
  346. }
  347. else
  348. {
  349. if ([delegate respondsToSelector:@selector(CTCPRequestReceived:ofType:fromUser:)])
  350. {
  351. char* request_string = malloc(request.length);
  352. [request getBytes:request_string length:request.length];
  353. char* request_type = strtok(request_string, " ");
  354. char* request_body = strtok(NULL, " " );
  355. [delegate CTCPRequestReceived:[NSData dataWithBytes:request_body length:strlen(request_body)+1] ofType:[NSData dataWithBytes:request_type length:strlen(request_type)+1] fromUser:nick];
  356. }
  357. }
  358. }
  359. - (void)CTCPReplyReceived:(NSData *)reply fromUser:(NSString *)nick
  360. {
  361. [delegate CTCPReplyReceived:reply fromUser:nick];
  362. }
  363. - (void)CTCPActionPerformed:(NSData *)action byUser:(NSString *)nick atTarget:(NSData *)target
  364. {
  365. IRCClientChannel* channel = channels[target];
  366. if(channel != nil)
  367. {
  368. // An action on a channel we're on
  369. [channel actionPerformed:action byUser:nick];
  370. }
  371. else
  372. {
  373. // An action in a private message
  374. NSString* actionString = [[NSString alloc] initWithData:action encoding:encoding];
  375. [delegate privateCTCPActionReceived:actionString fromUser:nick];
  376. }
  377. }
  378. - (void)unknownEventReceived:(NSData *)event from:(NSString *)origin params:(NSArray *)params
  379. {
  380. [delegate unknownEventReceived:event from:origin params:params];
  381. }
  382. -(void)numericEventReceived:(NSUInteger)event from:(NSString *)origin params:(NSArray *)params
  383. {
  384. [delegate numericEventReceived:event from:origin params:params];
  385. }
  386. @end
  387. #pragma mark - Useful helper functions
  388. NSString* getNickFromNickUserHost(NSString *nuh)
  389. {
  390. NSArray *nuhArray = [nuh componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"!@"]];
  391. if (nuhArray.count == 3)
  392. {
  393. return [NSString stringWithString:nuhArray[0]];
  394. }
  395. else
  396. {
  397. return [NSString stringWithString:nuh];
  398. }
  399. }
  400. NSString* getUserFromNickUserHost(NSString *nuh)
  401. {
  402. NSArray *nuhArray = [nuh componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"!@"]];
  403. if (nuhArray.count == 3)
  404. {
  405. return [NSString stringWithString:nuhArray[1]];
  406. }
  407. else
  408. {
  409. return nil;
  410. }
  411. }
  412. NSString* getHostFromNickUserHost(NSString *nuh)
  413. {
  414. NSArray *nuhArray = [nuh componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"!@"]];
  415. if (nuhArray.count == 3)
  416. {
  417. return [NSString stringWithString:nuhArray[2]];
  418. }
  419. else
  420. {
  421. return nil;
  422. }
  423. }
  424. /***********************************************/
  425. #pragma mark - Callback function implementations
  426. /***********************************************/
  427. /*!
  428. * The "on_connect" event is triggered when the client successfully
  429. * connects to the server, and could send commands to the server.
  430. * No extra params supplied; \a params is 0.
  431. */
  432. static void onConnect(irc_session_t *session, const char *event, const char *origin, const char **params, unsigned int count)
  433. {
  434. IRCClientSession* clientSession = (__bridge IRCClientSession *) irc_get_ctx(session);
  435. [clientSession connectionSucceeded];
  436. }
  437. /*!
  438. * The "nick" event is triggered when the client receives a NICK message,
  439. * meaning that someone (including you) on a channel with the client has
  440. * changed their nickname.
  441. *
  442. * \param origin the person, who changes the nick. Note that it can be you!
  443. * \param params[0] mandatory, contains the new nick.
  444. */
  445. static void onNick(irc_session_t *session, const char *event, const char *origin, const char **params, unsigned int count)
  446. {
  447. IRCClientSession* clientSession = (__bridge IRCClientSession *) irc_get_ctx(session);
  448. NSString *oldNick = @(origin);
  449. NSString *newNick = @(params[0]);
  450. [clientSession nickChangedFrom:oldNick to:newNick];
  451. }
  452. /*!
  453. * The "quit" event is triggered upon receipt of a QUIT message, which
  454. * means that someone on a channel with the client has disconnected.
  455. *
  456. * \param origin the person, who is disconnected
  457. * \param params[0] optional, contains the reason message (user-specified).
  458. */
  459. static void onQuit(irc_session_t *session, const char *event, const char *origin, const char **params, unsigned int count)
  460. {
  461. IRCClientSession *clientSession = (__bridge IRCClientSession *) irc_get_ctx(session);
  462. NSString *nick = @(origin);
  463. NSData *reason = nil;
  464. if(count > 0)
  465. {
  466. reason = [[NSData alloc] initWithBytes:params[0] length:strlen(params[0])];
  467. }
  468. [clientSession userQuit:nick withReason:reason];
  469. }
  470. /*!
  471. * The "join" event is triggered upon receipt of a JOIN message, which
  472. * means that someone has entered a channel that the client is on.
  473. *
  474. * \param origin the person, who joins the channel. By comparing it with
  475. * your own nickname, you can check whether your JOIN
  476. * command succeed.
  477. * \param params[0] mandatory, contains the channel name.
  478. */
  479. static void onJoinChannel(irc_session_t *session, const char *event, const char *origin, const char **params, unsigned int count)
  480. {
  481. IRCClientSession* clientSession = (__bridge IRCClientSession *) irc_get_ctx(session);
  482. NSString *nick = @(origin);
  483. NSData *channelName = [NSData dataWithBytes:params[0] length:strlen(params[0])];
  484. [clientSession userJoined:nick channel:channelName];
  485. }
  486. /*!
  487. * The "part" event is triggered upon receipt of a PART message, which
  488. * means that someone has left a channel that the client is on.
  489. *
  490. * \param origin the person, who leaves the channel. By comparing it with
  491. * your own nickname, you can check whether your PART
  492. * command succeed.
  493. * \param params[0] mandatory, contains the channel name.
  494. * \param params[1] optional, contains the reason message (user-defined).
  495. */
  496. static void onPartChannel(irc_session_t *session, const char *event, const char *origin, const char **params, unsigned int count)
  497. {
  498. IRCClientSession *clientSession = (__bridge IRCClientSession *) irc_get_ctx(session);
  499. NSString *nick = @(origin);
  500. NSData *channelName = [NSData dataWithBytes:params[0] length:strlen(params[0])];
  501. NSData *reason = nil;
  502. if (count > 1)
  503. {
  504. reason = [NSData dataWithBytes:params[1] length:strlen(params[1])+1];
  505. }
  506. [clientSession userParted:nick channel:channelName withReason:reason];
  507. }
  508. /*!
  509. * The "mode" event is triggered upon receipt of a channel MODE message,
  510. * which means that someone on a channel with the client has changed the
  511. * channel's parameters.
  512. *
  513. * \param origin the person, who changed the channel mode.
  514. * \param params[0] mandatory, contains the channel name.
  515. * \param params[1] mandatory, contains the changed channel mode, like
  516. * '+t', '-i' and so on.
  517. * \param params[2] optional, contains the mode argument (for example, a
  518. * key for +k mode, or user who got the channel operator status for
  519. * +o mode)
  520. */
  521. static void onMode(irc_session_t *session, const char *event, const char *origin, const char **params, unsigned int count)
  522. {
  523. IRCClientSession *clientSession = (__bridge IRCClientSession *) irc_get_ctx(session);
  524. NSString *nick = @(origin);
  525. NSData *channelName = [NSData dataWithBytes:params[0] length:strlen(params[0])];
  526. NSString *mode = @(params[1]);
  527. NSString *modeParams = nil;
  528. if (count > 2)
  529. {
  530. modeParams = @(params[2]);
  531. }
  532. [clientSession modeSet:mode withParams:modeParams forChannel:channelName by:nick];
  533. }
  534. /*!
  535. * The "umode" event is triggered upon receipt of a user MODE message,
  536. * which means that your user mode has been changed.
  537. *
  538. * \param origin the person, who changed the channel mode.
  539. * \param params[0] mandatory, contains the user changed mode, like
  540. * '+t', '-i' and so on.
  541. */
  542. static void onUserMode(irc_session_t *session, const char *event, const char *origin, const char **params, unsigned int count)
  543. {
  544. IRCClientSession *clientSession = (__bridge IRCClientSession *) irc_get_ctx(session);
  545. NSString* nick = @(origin);
  546. NSString *mode = @(params[0]);
  547. [clientSession modeSet:mode by:nick];
  548. }
  549. /*!
  550. * The "topic" event is triggered upon receipt of a TOPIC message, which
  551. * means that someone on a channel with the client has changed the
  552. * channel's topic.
  553. *
  554. * \param origin the person, who changes the channel topic.
  555. * \param params[0] mandatory, contains the channel name.
  556. * \param params[1] optional, contains the new topic.
  557. */
  558. static void onTopic(irc_session_t *session, const char *event, const char *origin, const char **params, unsigned int count)
  559. {
  560. IRCClientSession *clientSession = (__bridge IRCClientSession *) irc_get_ctx(session);
  561. NSString *nick = @(origin);
  562. NSData *channelName = [NSData dataWithBytes:params[0] length:strlen(params[0])];
  563. NSData *topic = nil;
  564. if (count > 1)
  565. {
  566. topic = [NSData dataWithBytes:params[1] length:strlen(params[1])];
  567. }
  568. [clientSession topicSet:topic forChannel:channelName by:nick];
  569. }
  570. /*!
  571. * The "kick" event is triggered upon receipt of a KICK message, which
  572. * means that someone on a channel with the client (or possibly the
  573. * client itself!) has been forcibly ejected.
  574. *
  575. * \param origin the person, who kicked the poor.
  576. * \param params[0] mandatory, contains the channel name.
  577. * \param params[1] optional, contains the nick of kicked person.
  578. * \param params[2] optional, contains the kick text
  579. */
  580. static void onKick(irc_session_t *session, const char *event, const char *origin, const char **params, unsigned int count)
  581. {
  582. IRCClientSession *clientSession = (__bridge IRCClientSession *) irc_get_ctx(session);
  583. NSString *byNick = @(origin);
  584. NSData *channelName = [NSData dataWithBytes:params[0] length:strlen(params[0])];
  585. NSString *nick = nil;
  586. NSData *reason = nil;
  587. if (count > 1)
  588. {
  589. nick = @(params[1]);
  590. }
  591. if (count > 2)
  592. {
  593. reason = [NSData dataWithBytes:params[2] length:strlen(params[2])];
  594. }
  595. [clientSession userKicked:nick fromChannel:channelName by:byNick withReason:reason];
  596. }
  597. /*!
  598. * The "channel" event is triggered upon receipt of a PRIVMSG message
  599. * to an entire channel, which means that someone on a channel with
  600. * the client has said something aloud. Your own messages don't trigger
  601. * PRIVMSG event.
  602. *
  603. * \param origin the person, who generates the message.
  604. * \param params[0] mandatory, contains the channel name.
  605. * \param params[1] optional, contains the message text
  606. */
  607. static void onChannelPrvmsg(irc_session_t *session, const char *event, const char *origin, const char **params, unsigned int count)
  608. {
  609. IRCClientSession *clientSession = (__bridge IRCClientSession *) irc_get_ctx(session);
  610. NSString *nick = @(origin);
  611. NSData *channelName = [NSData dataWithBytes:params[0] length:strlen(params[0])];
  612. NSData *message = nil;
  613. if (count > 1)
  614. {
  615. message = [NSData dataWithBytes:params[1] length:strlen(params[1])];
  616. }
  617. NSLog(@"onChannelPrvmsg");
  618. [clientSession messageSent:message toChannel:channelName byUser:nick];
  619. }
  620. /*!
  621. * The "privmsg" event is triggered upon receipt of a PRIVMSG message
  622. * which is addressed to one or more clients, which means that someone
  623. * is sending the client a private message.
  624. *
  625. * \param origin the person, who generates the message.
  626. * \param params[0] mandatory, contains your nick.
  627. * \param params[1] optional, contains the message text
  628. */
  629. static void onPrivmsg(irc_session_t *session, const char *event, const char *origin, const char **params, unsigned int count)
  630. {
  631. IRCClientSession *clientSession = (__bridge IRCClientSession *) irc_get_ctx(session);
  632. NSString *nick = @(origin);
  633. NSData *message = nil;
  634. if (count > 1)
  635. {
  636. message = [NSData dataWithBytes:params[1] length:strlen(params[1])];
  637. }
  638. [clientSession privateMessageReceived:message fromUser:nick];
  639. }
  640. /*!
  641. * The "notice" event is triggered upon receipt of a NOTICE message
  642. * which means that someone has sent the client a public or private
  643. * notice. According to RFC 1459, the only difference between NOTICE
  644. * and PRIVMSG is that you should NEVER automatically reply to NOTICE
  645. * messages. Unfortunately, this rule is frequently violated by IRC
  646. * servers itself - for example, NICKSERV messages require reply, and
  647. * are NOTICEs.
  648. *
  649. * \param origin the person, who generates the message.
  650. * \param params[0] mandatory, contains your nick.
  651. * \param params[1] optional, contains the message text
  652. */
  653. static void onNotice(irc_session_t *session, const char *event, const char *origin, const char **params, unsigned int count)
  654. {
  655. IRCClientSession *clientSession = (__bridge IRCClientSession *) irc_get_ctx(session);
  656. NSString *nick = @(origin);
  657. NSData *notice = nil;
  658. if (count > 1)
  659. {
  660. notice = [NSData dataWithBytes:params[1] length:strlen(params[1])];
  661. }
  662. [clientSession privateNoticeReceived:notice fromUser:nick];
  663. }
  664. /*!
  665. * The "notice" event is triggered upon receipt of a NOTICE message
  666. * which means that someone has sent the client a public or private
  667. * notice. According to RFC 1459, the only difference between NOTICE
  668. * and PRIVMSG is that you should NEVER automatically reply to NOTICE
  669. * messages. Unfortunately, this rule is frequently violated by IRC
  670. * servers itself - for example, NICKSERV messages require reply, and
  671. * are NOTICEs.
  672. *
  673. * \param origin the person, who generates the message.
  674. * \param params[0] mandatory, contains the target channel name.
  675. * \param params[1] optional, contains the message text.
  676. */
  677. static void onChannelNotice(irc_session_t *session, const char *event, const char *origin, const char **params, unsigned int count)
  678. {
  679. IRCClientSession *clientSession = (__bridge IRCClientSession *) irc_get_ctx(session);
  680. NSString *nick = @(origin);
  681. NSData *channelName = [NSData dataWithBytes:params[0] length:strlen(params[0])];
  682. NSData *notice = nil;
  683. if (count > 1)
  684. {
  685. notice = [NSData dataWithBytes:params[1] length:strlen(params[1])];
  686. }
  687. [clientSession noticeSent:notice toChannel:channelName byUser:nick];
  688. }
  689. /*!
  690. * The "invite" event is triggered upon receipt of an INVITE message,
  691. * which means that someone is permitting the client's entry into a +i
  692. * channel.
  693. *
  694. * \param origin the person, who INVITEs you.
  695. * \param params[0] mandatory, contains your nick.
  696. * \param params[1] mandatory, contains the channel name you're invited into.
  697. *
  698. * \sa irc_cmd_invite irc_cmd_chanmode_invite
  699. */
  700. static void onInvite(irc_session_t *session, const char *event, const char *origin, const char **params, unsigned int count)
  701. {
  702. IRCClientSession *clientSession = (__bridge IRCClientSession *) irc_get_ctx(session);
  703. NSString *nick = @(origin);
  704. NSData *channelName = [NSData dataWithBytes:params[1] length:strlen(params[1])];
  705. [clientSession invitedToChannel:channelName by:nick];
  706. }
  707. /*!
  708. * The "ctcp" event is triggered when the client receives the CTCP
  709. * request. By default, the built-in CTCP request handler is used. The
  710. * build-in handler automatically replies on most CTCP messages, so you
  711. * will rarely need to override it.
  712. *
  713. * \param origin the person, who generates the message.
  714. * \param params[0] mandatory, the complete CTCP message, including its
  715. * arguments.
  716. *
  717. * Mirc generates PING, FINGER, VERSION, TIME and ACTION messages,
  718. * check the source code of \c libirc_event_ctcp_internal function to
  719. * see how to write your own CTCP request handler. Also you may find
  720. * useful this question in FAQ: \ref faq4
  721. */
  722. static void onCtcpRequest(irc_session_t *session, const char *event, const char *origin, const char **params, unsigned int count)
  723. {
  724. IRCClientSession *clientSession = (__bridge IRCClientSession *) irc_get_ctx(session);
  725. NSString *nick = @(origin);
  726. NSData* request = [NSData dataWithBytes:params[0] length:strlen(params[0])];
  727. [clientSession CTCPRequestReceived:request fromUser:nick];
  728. }
  729. /*!
  730. * The "ctcp" event is triggered when the client receives the CTCP reply.
  731. *
  732. * \param origin the person, who generates the message.
  733. * \param params[0] mandatory, the CTCP message itself with its arguments.
  734. */
  735. static void onCtcpReply(irc_session_t *session, const char *event, const char *origin, const char **params, unsigned int count)
  736. {
  737. IRCClientSession *clientSession = (__bridge IRCClientSession *) irc_get_ctx(session);
  738. NSString *nick = @(origin);
  739. NSData *reply = [NSData dataWithBytes:params[0] length:strlen(params[0])];
  740. [clientSession CTCPReplyReceived:reply fromUser:nick];
  741. }
  742. /*!
  743. * The "action" event is triggered when the client receives the CTCP
  744. * ACTION message. These messages usually looks like:\n
  745. * \code
  746. * [23:32:55] * Tim gonna sleep.
  747. * \endcode
  748. *
  749. * \param origin the person, who generates the message.
  750. * \param params[0] mandatory, the target of the message.
  751. * \param params[1] mandatory, the ACTION message.
  752. */
  753. static void onCtcpAction(irc_session_t *session, const char *event, const char *origin, const char **params, unsigned int count)
  754. {
  755. IRCClientSession *clientSession = (__bridge IRCClientSession *) irc_get_ctx(session);
  756. NSString *nick = @(origin);
  757. NSData *target = [NSData dataWithBytes:params[0] length:strlen(params[0])];
  758. NSData *action = [NSData dataWithBytes:params[1] length:strlen(params[1])];
  759. [clientSession CTCPActionPerformed:action byUser:nick atTarget:target];
  760. }
  761. /*!
  762. * The "unknown" event is triggered upon receipt of any number of
  763. * unclassifiable miscellaneous messages, which aren't handled by the
  764. * library.
  765. */
  766. static void onUnknownEvent(irc_session_t *session, const char *event, const char *origin, const char **params, unsigned int count)
  767. {
  768. IRCClientSession *clientSession = (__bridge IRCClientSession *) irc_get_ctx(session);
  769. NSData *eventString = [NSData dataWithBytes:event length:strlen(event)];
  770. NSString *sender = nil;
  771. if (origin != NULL)
  772. sender = @(origin);
  773. NSMutableArray *paramsArray = [[NSMutableArray alloc] init];
  774. for (unsigned int i = 0; i < count; i++)
  775. [paramsArray addObject:[NSData dataWithBytes:params[i] length:strlen(params[i])]];
  776. [clientSession unknownEventReceived:eventString from:sender params:[paramsArray copy]];
  777. }
  778. /*!
  779. * The "numeric" event is triggered upon receipt of any numeric response
  780. * from the server. There is a lot of such responses, see the full list
  781. * here: \ref rfcnumbers.
  782. *
  783. * See the params in ::irc_eventcode_callback_t specification.
  784. */
  785. static void onNumericEvent(irc_session_t * session, unsigned int event, const char * origin, const char ** params, unsigned int count)
  786. {
  787. IRCClientSession *clientSession = (__bridge IRCClientSession *) irc_get_ctx(session);
  788. NSUInteger eventNumber = event;
  789. NSString *sender = @(origin);
  790. NSMutableArray *paramsArray = [[NSMutableArray alloc] init];
  791. for (unsigned int i = 0; i < count; i++)
  792. [paramsArray addObject:[NSData dataWithBytes:params[i] length:strlen(params[i])]];
  793. [clientSession numericEventReceived:eventNumber from:sender params:[paramsArray copy]];
  794. }