IRC client framework (wrapper around libircclient library).
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

IRCClientSession.m 31KB

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