IRC client framework (wrapper around libircclient library).
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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. }