LibIRCClient 1.10 Used by Probotic
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.
Ce dépôt est archivé. Vous pouvez voir les fichiers et le cloner, mais vous ne pouvez pas pousser ni ouvrir de ticket/demande d'ajout.

1288 lignes
30KB

  1. /*
  2. * Copyright (C) 2004-2012 George Yunaev gyunaev@ulduzsoft.com
  3. *
  4. * This library is free software; you can redistribute it and/or modify it
  5. * under the terms of the GNU Lesser General Public License as published by
  6. * the Free Software Foundation; either version 3 of the License, or (at your
  7. * option) any later version.
  8. *
  9. * This library is distributed in the hope that it will be useful, but WITHOUT
  10. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
  12. * License for more details.
  13. */
  14. #define IS_DEBUG_ENABLED(s) ((s)->options & LIBIRC_OPTION_DEBUG)
  15. #include "portable.c"
  16. #include "sockets.c"
  17. #include "libircclient.h"
  18. #include "session.h"
  19. #include "utils.c"
  20. #include "errors.c"
  21. #include "colors.c"
  22. #include "dcc.c"
  23. #include "ssl.c"
  24. #ifdef _MSC_VER
  25. /*
  26. * The debugger of MSVC 2005 does not like strdup.
  27. * It complains about heap corruption when free is called.
  28. * Use _strdup instead.
  29. */
  30. #undef strdup
  31. #define strdup _strdup
  32. #endif
  33. #if defined (WIN32_DLL)
  34. static int winsock_refcount = 0;
  35. #endif
  36. irc_session_t * irc_create_session (irc_callbacks_t * callbacks)
  37. {
  38. irc_session_t * session;
  39. #if defined (WIN32_DLL)
  40. // From MSDN: The WSAStartup function typically leads to protocol-specific helper
  41. // DLLs being loaded. As a result, the WSAStartup function should not be called
  42. // from the DllMain function in a application DLL. This can potentially cause deadlocks.
  43. if ( winsock_refcount == 0 )
  44. {
  45. WORD wVersionRequested = MAKEWORD (1, 1);
  46. WSADATA wsaData;
  47. if ( WSAStartup (wVersionRequested, &wsaData) != 0 )
  48. return 0;
  49. winsock_refcount++;
  50. }
  51. #endif
  52. session = malloc (sizeof(irc_session_t));
  53. if ( !session )
  54. return 0;
  55. memset (session, 0, sizeof(irc_session_t));
  56. session->sock = -1;
  57. if ( libirc_mutex_init (&session->mutex_session)
  58. || libirc_mutex_init (&session->mutex_dcc) )
  59. {
  60. free (session);
  61. return 0;
  62. }
  63. session->dcc_last_id = 1;
  64. session->dcc_timeout = 60;
  65. memcpy (&session->callbacks, callbacks, sizeof(irc_callbacks_t));
  66. if ( !session->callbacks.event_ctcp_req )
  67. session->callbacks.event_ctcp_req = libirc_event_ctcp_internal;
  68. return session;
  69. }
  70. static void free_ircsession_strings (irc_session_t * session)
  71. {
  72. if ( session->realname )
  73. free (session->realname);
  74. if ( session->username )
  75. free (session->username);
  76. if ( session->nick )
  77. free (session->nick);
  78. if ( session->server )
  79. free (session->server);
  80. if ( session->server_password )
  81. free (session->server_password);
  82. session->realname = 0;
  83. session->username = 0;
  84. session->nick = 0;
  85. session->server = 0;
  86. session->server_password = 0;
  87. }
  88. void irc_destroy_session (irc_session_t * session)
  89. {
  90. free_ircsession_strings( session );
  91. // The CTCP VERSION must be freed only now
  92. if ( session->ctcp_version )
  93. free (session->ctcp_version);
  94. if ( session->sock >= 0 )
  95. socket_close (&session->sock);
  96. #if defined (ENABLE_THREADS)
  97. libirc_mutex_destroy (&session->mutex_session);
  98. #endif
  99. #if defined (ENABLE_SSL)
  100. if ( session->ssl )
  101. SSL_free( session->ssl );
  102. #endif
  103. /*
  104. * delete DCC data
  105. * libirc_remove_dcc_session removes the DCC session from the list.
  106. */
  107. while ( session->dcc_sessions )
  108. libirc_remove_dcc_session (session, session->dcc_sessions, 0);
  109. libirc_mutex_destroy (&session->mutex_dcc);
  110. free (session);
  111. #if defined (WIN32_DLL)
  112. if ( --winsock_refcount == 0 )
  113. WSACleanup();
  114. #endif
  115. }
  116. int irc_connect (irc_session_t * session,
  117. const char * server,
  118. unsigned short port,
  119. const char * server_password,
  120. const char * nick,
  121. const char * username,
  122. const char * realname)
  123. {
  124. struct sockaddr_in saddr;
  125. char * p;
  126. // Check and copy all the specified fields
  127. if ( !server || !nick )
  128. {
  129. session->lasterror = LIBIRC_ERR_INVAL;
  130. return 1;
  131. }
  132. if ( session->state != LIBIRC_STATE_INIT )
  133. {
  134. session->lasterror = LIBIRC_ERR_STATE;
  135. return 1;
  136. }
  137. // Free the strings if defined; may be the case when the session is reused after the connection fails
  138. free_ircsession_strings( session );
  139. // Handle the server # prefix (SSL)
  140. if ( server[0] == SSL_PREFIX )
  141. {
  142. #if defined (ENABLE_SSL)
  143. server++;
  144. session->flags |= SESSIONFL_SSL_CONNECTION;
  145. #else
  146. session->lasterror = LIBIRC_ERR_SSL_NOT_SUPPORTED;
  147. return 1;
  148. #endif
  149. }
  150. if ( username )
  151. session->username = strdup (username);
  152. if ( server_password )
  153. session->server_password = strdup (server_password);
  154. if ( realname )
  155. session->realname = strdup (realname);
  156. session->nick = strdup (nick);
  157. session->server = strdup (server);
  158. // If port number is zero and server contains the port, parse it
  159. if ( port == 0 && (p = strchr( session->server, ':' )) != 0 )
  160. {
  161. // Terminate the string and parse the port number
  162. *p++ = '\0';
  163. port = atoi( p );
  164. }
  165. // IPv4 address resolving
  166. memset( &saddr, 0, sizeof(saddr) );
  167. saddr.sin_family = AF_INET;
  168. saddr.sin_port = htons (port);
  169. saddr.sin_addr.s_addr = inet_addr( session->server );
  170. if ( saddr.sin_addr.s_addr == INADDR_NONE )
  171. {
  172. struct hostent *hp;
  173. #if defined HAVE_GETHOSTBYNAME_R
  174. int tmp_errno;
  175. struct hostent tmp_hostent;
  176. char buf[2048];
  177. if ( gethostbyname_r (session->server, &tmp_hostent, buf, sizeof(buf), &hp, &tmp_errno) )
  178. hp = 0;
  179. #else
  180. hp = gethostbyname (session->server);
  181. #endif // HAVE_GETHOSTBYNAME_R
  182. if ( !hp )
  183. {
  184. session->lasterror = LIBIRC_ERR_RESOLV;
  185. return 1;
  186. }
  187. memcpy (&saddr.sin_addr, hp->h_addr, (size_t) hp->h_length);
  188. }
  189. // create the IRC server socket
  190. if ( socket_create( PF_INET, SOCK_STREAM, &session->sock)
  191. || socket_make_nonblocking (&session->sock) )
  192. {
  193. session->lasterror = LIBIRC_ERR_SOCKET;
  194. return 1;
  195. }
  196. #if defined (ENABLE_SSL)
  197. // Init the SSL stuff
  198. if ( session->flags & SESSIONFL_SSL_CONNECTION )
  199. {
  200. int rc = ssl_init( session );
  201. if ( rc != 0 )
  202. {
  203. session->lasterror = rc;
  204. return 1;
  205. }
  206. }
  207. #endif
  208. // and connect to the IRC server
  209. if ( socket_connect (&session->sock, (struct sockaddr *) &saddr, sizeof(saddr)) )
  210. {
  211. session->lasterror = LIBIRC_ERR_CONNECT;
  212. return 1;
  213. }
  214. session->state = LIBIRC_STATE_CONNECTING;
  215. session->flags = SESSIONFL_USES_IPV6; // reset in case of reconnect
  216. return 0;
  217. }
  218. int irc_connect6 (irc_session_t * session,
  219. const char * server,
  220. unsigned short port,
  221. const char * server_password,
  222. const char * nick,
  223. const char * username,
  224. const char * realname)
  225. {
  226. #if defined (ENABLE_IPV6)
  227. struct sockaddr_in6 saddr;
  228. struct addrinfo ainfo, *res = NULL;
  229. char portStr[32], *p;
  230. #if defined (_WIN32)
  231. int addrlen = sizeof(saddr);
  232. HMODULE hWsock;
  233. getaddrinfo_ptr_t getaddrinfo_ptr;
  234. freeaddrinfo_ptr_t freeaddrinfo_ptr;
  235. int resolvesuccess = 0;
  236. #endif
  237. // Check and copy all the specified fields
  238. if ( !server || !nick )
  239. {
  240. session->lasterror = LIBIRC_ERR_INVAL;
  241. return 1;
  242. }
  243. if ( session->state != LIBIRC_STATE_INIT )
  244. {
  245. session->lasterror = LIBIRC_ERR_STATE;
  246. return 1;
  247. }
  248. // Free the strings if defined; may be the case when the session is reused after the connection fails
  249. free_ircsession_strings( session );
  250. // Handle the server # prefix (SSL)
  251. if ( server[0] == SSL_PREFIX )
  252. {
  253. #if defined (ENABLE_SSL)
  254. server++;
  255. session->flags |= SESSIONFL_SSL_CONNECTION;
  256. #else
  257. session->lasterror = LIBIRC_ERR_SSL_NOT_SUPPORTED;
  258. return 1;
  259. #endif
  260. }
  261. if ( username )
  262. session->username = strdup (username);
  263. if ( server_password )
  264. session->server_password = strdup (server_password);
  265. if ( realname )
  266. session->realname = strdup (realname);
  267. session->nick = strdup (nick);
  268. session->server = strdup (server);
  269. // If port number is zero and server contains the port, parse it
  270. if ( port == 0 && (p = strchr( session->server, ':' )) != 0 )
  271. {
  272. // Terminate the string and parse the port number
  273. *p++ = '\0';
  274. port = atoi( p );
  275. }
  276. memset( &saddr, 0, sizeof(saddr) );
  277. saddr.sin6_family = AF_INET6;
  278. saddr.sin6_port = htons (port);
  279. sprintf( portStr, "%u", (unsigned)port );
  280. #if defined (_WIN32)
  281. if ( WSAStringToAddressA( (LPSTR)session->server, AF_INET6, NULL, (struct sockaddr *)&saddr, &addrlen ) == SOCKET_ERROR )
  282. {
  283. hWsock = LoadLibraryA("ws2_32");
  284. if (hWsock)
  285. {
  286. /* Determine functions at runtime, because windows systems < XP do not
  287. * support getaddrinfo. */
  288. getaddrinfo_ptr = (getaddrinfo_ptr_t)GetProcAddress(hWsock, "getaddrinfo");
  289. freeaddrinfo_ptr = (freeaddrinfo_ptr_t)GetProcAddress(hWsock, "freeaddrinfo");
  290. if (getaddrinfo_ptr && freeaddrinfo_ptr)
  291. {
  292. memset(&ainfo, 0, sizeof(ainfo));
  293. ainfo.ai_family = AF_INET6;
  294. ainfo.ai_socktype = SOCK_STREAM;
  295. ainfo.ai_protocol = 0;
  296. if ( getaddrinfo_ptr(session->server, portStr, &ainfo, &res) == 0 && res )
  297. {
  298. resolvesuccess = 1;
  299. memcpy( &saddr, res->ai_addr, res->ai_addrlen );
  300. freeaddrinfo_ptr( res );
  301. }
  302. }
  303. FreeLibrary(hWsock);
  304. }
  305. if (!resolvesuccess)
  306. {
  307. session->lasterror = LIBIRC_ERR_RESOLV;
  308. return 1;
  309. }
  310. }
  311. #else
  312. if ( inet_pton( AF_INET6, session->server, (void*) &saddr.sin6_addr ) <= 0 )
  313. {
  314. memset( &ainfo, 0, sizeof(ainfo) );
  315. ainfo.ai_family = AF_INET6;
  316. ainfo.ai_socktype = SOCK_STREAM;
  317. ainfo.ai_protocol = 0;
  318. if ( getaddrinfo( session->server, portStr, &ainfo, &res ) || !res )
  319. {
  320. session->lasterror = LIBIRC_ERR_RESOLV;
  321. return 1;
  322. }
  323. memcpy( &saddr, res->ai_addr, res->ai_addrlen );
  324. freeaddrinfo( res );
  325. }
  326. #endif
  327. // create the IRC server socket
  328. if ( socket_create( PF_INET6, SOCK_STREAM, &session->sock)
  329. || socket_make_nonblocking (&session->sock) )
  330. {
  331. session->lasterror = LIBIRC_ERR_SOCKET;
  332. return 1;
  333. }
  334. #if defined (ENABLE_SSL)
  335. // Init the SSL stuff
  336. if ( session->flags & SESSIONFL_SSL_CONNECTION )
  337. {
  338. int rc = ssl_init( session );
  339. if ( rc != 0 )
  340. return rc;
  341. }
  342. #endif
  343. // and connect to the IRC server
  344. if ( socket_connect (&session->sock, (struct sockaddr *) &saddr, sizeof(saddr)) )
  345. {
  346. session->lasterror = LIBIRC_ERR_CONNECT;
  347. return 1;
  348. }
  349. session->state = LIBIRC_STATE_CONNECTING;
  350. session->flags = 0; // reset in case of reconnect
  351. return 0;
  352. #else
  353. session->lasterror = LIBIRC_ERR_NOIPV6;
  354. return 1;
  355. #endif
  356. }
  357. int irc_is_connected (irc_session_t * session)
  358. {
  359. return (session->state == LIBIRC_STATE_CONNECTED
  360. || session->state == LIBIRC_STATE_CONNECTING) ? 1 : 0;
  361. }
  362. int irc_run (irc_session_t * session)
  363. {
  364. if ( session->state != LIBIRC_STATE_CONNECTING )
  365. {
  366. session->lasterror = LIBIRC_ERR_STATE;
  367. return 1;
  368. }
  369. while ( irc_is_connected(session) )
  370. {
  371. struct timeval tv;
  372. fd_set in_set, out_set;
  373. int maxfd = 0;
  374. tv.tv_usec = 250000;
  375. tv.tv_sec = 0;
  376. // Init sets
  377. FD_ZERO (&in_set);
  378. FD_ZERO (&out_set);
  379. irc_add_select_descriptors (session, &in_set, &out_set, &maxfd);
  380. if ( select (maxfd + 1, &in_set, &out_set, 0, &tv) < 0 )
  381. {
  382. if ( socket_error() == EINTR )
  383. continue;
  384. session->lasterror = LIBIRC_ERR_TERMINATED;
  385. return 1;
  386. }
  387. if ( irc_process_select_descriptors (session, &in_set, &out_set) )
  388. return 1;
  389. }
  390. return 0;
  391. }
  392. int irc_add_select_descriptors (irc_session_t * session, fd_set *in_set, fd_set *out_set, int * maxfd)
  393. {
  394. if ( session->sock < 0
  395. || session->state == LIBIRC_STATE_INIT
  396. || session->state == LIBIRC_STATE_DISCONNECTED )
  397. {
  398. session->lasterror = LIBIRC_ERR_STATE;
  399. return 1;
  400. }
  401. libirc_mutex_lock (&session->mutex_session);
  402. switch (session->state)
  403. {
  404. case LIBIRC_STATE_CONNECTING:
  405. // While connection, only out_set descriptor should be set
  406. libirc_add_to_set (session->sock, out_set, maxfd);
  407. break;
  408. case LIBIRC_STATE_CONNECTED:
  409. // Add input descriptor if there is space in input buffer
  410. if ( session->incoming_offset < (sizeof (session->incoming_buf) - 1)
  411. || (session->flags & SESSIONFL_SSL_WRITE_WANTS_READ) != 0 )
  412. libirc_add_to_set (session->sock, in_set, maxfd);
  413. // Add output descriptor if there is something in output buffer
  414. if ( libirc_findcrlf (session->outgoing_buf, session->outgoing_offset) > 0
  415. || (session->flags & SESSIONFL_SSL_READ_WANTS_WRITE) != 0 )
  416. libirc_add_to_set (session->sock, out_set, maxfd);
  417. break;
  418. }
  419. libirc_mutex_unlock (&session->mutex_session);
  420. libirc_dcc_add_descriptors (session, in_set, out_set, maxfd);
  421. return 0;
  422. }
  423. static void libirc_process_incoming_data (irc_session_t * session, size_t process_length)
  424. {
  425. #define MAX_PARAMS_ALLOWED 10
  426. char buf[2*512], *p, *s;
  427. const char * command = 0, *prefix = 0, *params[MAX_PARAMS_ALLOWED+1];
  428. int code = 0, paramindex = 0;
  429. char *buf_end = buf + process_length;
  430. if ( process_length > sizeof(buf) )
  431. abort(); // should be impossible
  432. memcpy (buf, session->incoming_buf, process_length);
  433. buf[process_length] = '\0';
  434. memset ((char *)params, 0, sizeof(params));
  435. p = buf;
  436. /*
  437. * From RFC 1459:
  438. * <message> ::= [':' <prefix> <SPACE> ] <command> <params> <crlf>
  439. * <prefix> ::= <servername> | <nick> [ '!' <user> ] [ '@' <host> ]
  440. * <command> ::= <letter> { <letter> } | <number> <number> <number>
  441. * <SPACE> ::= ' ' { ' ' }
  442. * <params> ::= <SPACE> [ ':' <trailing> | <middle> <params> ]
  443. * <middle> ::= <Any *non-empty* sequence of octets not including SPACE
  444. * or NUL or CR or LF, the first of which may not be ':'>
  445. * <trailing> ::= <Any, possibly *empty*, sequence of octets not including
  446. * NUL or CR or LF>
  447. */
  448. // Parse <prefix>
  449. if ( buf[0] == ':' )
  450. {
  451. while ( *p && *p != ' ')
  452. p++;
  453. *p++ = '\0';
  454. // we use buf+1 to skip the leading colon
  455. prefix = buf + 1;
  456. // If LIBIRC_OPTION_STRIPNICKS is set, we should 'clean up' nick
  457. // right here
  458. if ( session->options & LIBIRC_OPTION_STRIPNICKS )
  459. {
  460. for ( s = buf + 1; *s; s++ )
  461. {
  462. if ( *s == '@' || *s == '!' )
  463. {
  464. *s = '\0';
  465. break;
  466. }
  467. }
  468. }
  469. }
  470. // Parse <command>
  471. if ( isdigit (p[0]) && isdigit (p[1]) && isdigit (p[2]) )
  472. {
  473. p[3] = '\0';
  474. code = atoi (p);
  475. p += 4;
  476. }
  477. else
  478. {
  479. s = p;
  480. while ( *p && *p != ' ')
  481. p++;
  482. *p++ = '\0';
  483. command = s;
  484. }
  485. // Parse middle/params
  486. while ( *p && paramindex < MAX_PARAMS_ALLOWED )
  487. {
  488. // beginning from ':', this is the last param
  489. if ( *p == ':' )
  490. {
  491. params[paramindex++] = p + 1; // skip :
  492. break;
  493. }
  494. // Just a param
  495. for ( s = p; *p && *p != ' '; p++ )
  496. ;
  497. params[paramindex++] = s;
  498. if ( !*p )
  499. break;
  500. *p++ = '\0';
  501. }
  502. // Handle PING/PONG
  503. if ( command && !strncmp (command, "PING", buf_end - command) && params[0] )
  504. {
  505. irc_send_raw (session, "PONG %s", params[0]);
  506. return;
  507. }
  508. // and dump
  509. if ( code )
  510. {
  511. // We use SESSIONFL_MOTD_RECEIVED flag to check whether it is the first
  512. // RPL_ENDOFMOTD or ERR_NOMOTD after the connection.
  513. if ( (code == 1 || code == 376 || code == 422) && !(session->flags & SESSIONFL_MOTD_RECEIVED ) )
  514. {
  515. session->flags |= SESSIONFL_MOTD_RECEIVED;
  516. if ( session->callbacks.event_connect )
  517. (*session->callbacks.event_connect) (session, "CONNECT", prefix, params, paramindex);
  518. }
  519. if ( session->callbacks.event_numeric )
  520. (*session->callbacks.event_numeric) (session, code, prefix, params, paramindex);
  521. }
  522. else
  523. {
  524. if ( !strncmp (command, "NICK", buf_end - command) )
  525. {
  526. /*
  527. * If we're changed our nick, we should save it.
  528. */
  529. char nickbuf[256];
  530. irc_target_get_nick (prefix, nickbuf, sizeof(nickbuf));
  531. if ( !strncmp (nickbuf, session->nick, strlen(session->nick)) && paramindex > 0 )
  532. {
  533. free (session->nick);
  534. session->nick = strdup (params[0]);
  535. }
  536. if ( session->callbacks.event_nick )
  537. (*session->callbacks.event_nick) (session, command, prefix, params, paramindex);
  538. }
  539. else if ( !strncmp (command, "QUIT", buf_end - command) )
  540. {
  541. if ( session->callbacks.event_quit )
  542. (*session->callbacks.event_quit) (session, command, prefix, params, paramindex);
  543. }
  544. else if ( !strncmp (command, "JOIN", buf_end - command) )
  545. {
  546. if ( session->callbacks.event_join )
  547. (*session->callbacks.event_join) (session, command, prefix, params, paramindex);
  548. }
  549. else if ( !strncmp (command, "PART", buf_end - command) )
  550. {
  551. if ( session->callbacks.event_part )
  552. (*session->callbacks.event_part) (session, command, prefix, params, paramindex);
  553. }
  554. else if ( !strncmp (command, "MODE", buf_end - command) )
  555. {
  556. if ( paramindex > 0 && !strncmp (params[0], session->nick, strlen(session->nick)) )
  557. {
  558. params[0] = params[1];
  559. paramindex = 1;
  560. if ( session->callbacks.event_umode )
  561. (*session->callbacks.event_umode) (session, command, prefix, params, paramindex);
  562. }
  563. else
  564. {
  565. if ( session->callbacks.event_mode )
  566. (*session->callbacks.event_mode) (session, command, prefix, params, paramindex);
  567. }
  568. }
  569. else if ( !strncmp (command, "TOPIC", buf_end - command) )
  570. {
  571. if ( session->callbacks.event_topic )
  572. (*session->callbacks.event_topic) (session, command, prefix, params, paramindex);
  573. }
  574. else if ( !strncmp (command, "KICK", buf_end - command) )
  575. {
  576. if ( session->callbacks.event_kick )
  577. (*session->callbacks.event_kick) (session, command, prefix, params, paramindex);
  578. }
  579. else if ( !strncmp (command, "PRIVMSG", buf_end - command) )
  580. {
  581. if ( paramindex > 1 )
  582. {
  583. size_t msglen = strlen (params[1]);
  584. /*
  585. * Check for CTCP request (a CTCP message starts from 0x01
  586. * and ends by 0x01
  587. */
  588. if ( params[1][0] == 0x01 && params[1][msglen-1] == 0x01 )
  589. {
  590. char ctcp_buf[128];
  591. msglen -= 2;
  592. if ( msglen > sizeof(ctcp_buf) - 1 )
  593. msglen = sizeof(ctcp_buf) - 1;
  594. memcpy (ctcp_buf, params[1] + 1, msglen);
  595. ctcp_buf[msglen] = '\0';
  596. if ( !strncasecmp(ctcp_buf, "DCC ", 4) )
  597. libirc_dcc_request (session, prefix, ctcp_buf);
  598. else if ( !strncasecmp( ctcp_buf, "ACTION ", 7)
  599. && session->callbacks.event_ctcp_action )
  600. {
  601. params[1] = ctcp_buf + 7; // the length of "ACTION "
  602. paramindex = 2;
  603. (*session->callbacks.event_ctcp_action) (session, "ACTION", prefix, params, paramindex);
  604. }
  605. else
  606. {
  607. params[0] = ctcp_buf;
  608. paramindex = 1;
  609. if ( session->callbacks.event_ctcp_req )
  610. (*session->callbacks.event_ctcp_req) (session, "CTCP", prefix, params, paramindex);
  611. }
  612. }
  613. else if ( !strncasecmp (params[0], session->nick, strlen(session->nick) ) )
  614. {
  615. if ( session->callbacks.event_privmsg )
  616. (*session->callbacks.event_privmsg) (session, "PRIVMSG", prefix, params, paramindex);
  617. }
  618. else
  619. {
  620. if ( session->callbacks.event_channel )
  621. (*session->callbacks.event_channel) (session, "CHANNEL", prefix, params, paramindex);
  622. }
  623. }
  624. }
  625. else if ( !strncmp (command, "NOTICE", buf_end - command) )
  626. {
  627. size_t msglen = strlen (params[1]);
  628. /*
  629. * Check for CTCP request (a CTCP message starts from 0x01
  630. * and ends by 0x01
  631. */
  632. if ( paramindex > 1 && params[1][0] == 0x01 && params[1][msglen-1] == 0x01 )
  633. {
  634. char ctcp_buf[512];
  635. msglen -= 2;
  636. if ( msglen > sizeof(ctcp_buf) - 1 )
  637. msglen = sizeof(ctcp_buf) - 1;
  638. memcpy (ctcp_buf, params[1] + 1, msglen);
  639. ctcp_buf[msglen] = '\0';
  640. params[0] = ctcp_buf;
  641. paramindex = 1;
  642. if ( session->callbacks.event_ctcp_rep )
  643. (*session->callbacks.event_ctcp_rep) (session, "CTCP", prefix, params, paramindex);
  644. }
  645. else if ( !strncasecmp (params[0], session->nick, strlen(session->nick) ) )
  646. {
  647. if ( session->callbacks.event_notice )
  648. (*session->callbacks.event_notice) (session, command, prefix, params, paramindex);
  649. } else {
  650. if ( session->callbacks.event_channel_notice )
  651. (*session->callbacks.event_channel_notice) (session, command, prefix, params, paramindex);
  652. }
  653. }
  654. else if ( !strncmp (command, "INVITE", buf_end - command) )
  655. {
  656. if ( session->callbacks.event_invite )
  657. (*session->callbacks.event_invite) (session, command, prefix, params, paramindex);
  658. }
  659. else if ( !strncmp (command, "KILL", buf_end - command) )
  660. {
  661. ; /* ignore this event - not all servers generate this */
  662. }
  663. else
  664. {
  665. /*
  666. * The "unknown" event is triggered upon receipt of any number of
  667. * unclassifiable miscellaneous messages, which aren't handled by
  668. * the library.
  669. */
  670. if ( session->callbacks.event_unknown )
  671. (*session->callbacks.event_unknown) (session, command, prefix, params, paramindex);
  672. }
  673. }
  674. }
  675. int irc_process_select_descriptors (irc_session_t * session, fd_set *in_set, fd_set *out_set)
  676. {
  677. char buf[256], hname[256];
  678. if ( session->sock < 0
  679. || session->state == LIBIRC_STATE_INIT
  680. || session->state == LIBIRC_STATE_DISCONNECTED )
  681. {
  682. session->lasterror = LIBIRC_ERR_STATE;
  683. return 1;
  684. }
  685. session->lasterror = 0;
  686. libirc_dcc_process_descriptors (session, in_set, out_set);
  687. // Handle "connection succeed" / "connection failed"
  688. if ( session->state == LIBIRC_STATE_CONNECTING )
  689. {
  690. // If the socket is not connected yet, wait longer - it is not an error
  691. if ( !FD_ISSET (session->sock, out_set) )
  692. return 0;
  693. // Now we have to determine whether the socket is connected
  694. // or the connect is failed
  695. struct sockaddr_storage saddr, laddr;
  696. socklen_t slen = sizeof(saddr);
  697. socklen_t llen = sizeof(laddr);
  698. if ( getsockname (session->sock, (struct sockaddr*)&laddr, &llen) < 0
  699. || getpeername (session->sock, (struct sockaddr*)&saddr, &slen) < 0 )
  700. {
  701. // connection failed
  702. session->lasterror = LIBIRC_ERR_CONNECT;
  703. session->state = LIBIRC_STATE_DISCONNECTED;
  704. return 1;
  705. }
  706. if (saddr.ss_family == AF_INET)
  707. memcpy (&session->local_addr, &((struct sockaddr_in *)&laddr)->sin_addr, sizeof(struct in_addr));
  708. else
  709. memcpy (&session->local_addr, &((struct sockaddr_in6 *)&laddr)->sin6_addr, sizeof(struct in6_addr));
  710. #if defined (ENABLE_DEBUG)
  711. if ( IS_DEBUG_ENABLED(session) )
  712. fprintf (stderr, "[DEBUG] Detected local address: %s\n", inet_ntoa(session->local_addr));
  713. #endif
  714. session->state = LIBIRC_STATE_CONNECTED;
  715. // Get the hostname
  716. if ( gethostname (hname, sizeof(hname)) < 0 )
  717. strcpy (hname, "unknown");
  718. // Prepare the data, which should be sent to the server
  719. if ( session->server_password )
  720. {
  721. snprintf (buf, sizeof(buf), "PASS %s", session->server_password);
  722. irc_send_raw (session, buf);
  723. }
  724. snprintf (buf, sizeof(buf), "NICK %s", session->nick);
  725. irc_send_raw (session, buf);
  726. /*
  727. * RFC 1459 states that "hostname and servername are normally
  728. * ignored by the IRC server when the USER command comes from
  729. * a directly connected client (for security reasons)", therefore
  730. * we don't need them.
  731. */
  732. snprintf (buf, sizeof(buf), "USER %s unknown unknown :%s",
  733. session->username ? session->username : "nobody",
  734. session->realname ? session->realname : "noname");
  735. irc_send_raw (session, buf);
  736. return 0;
  737. }
  738. if ( session->state != LIBIRC_STATE_CONNECTED )
  739. {
  740. session->lasterror = LIBIRC_ERR_STATE;
  741. return 1;
  742. }
  743. // Hey, we've got something to read!
  744. if ( FD_ISSET (session->sock, in_set) )
  745. {
  746. int offset, length = session_socket_read( session );
  747. if ( length < 0 )
  748. {
  749. if ( session->lasterror == 0 )
  750. session->lasterror = (length == 0 ? LIBIRC_ERR_CLOSED : LIBIRC_ERR_TERMINATED);
  751. session->state = LIBIRC_STATE_DISCONNECTED;
  752. return 1;
  753. }
  754. session->incoming_offset += length;
  755. // process the incoming data
  756. while ( (offset = libirc_findcrlf (session->incoming_buf, session->incoming_offset)) > 0 )
  757. {
  758. #if defined (ENABLE_DEBUG)
  759. if ( IS_DEBUG_ENABLED(session) )
  760. libirc_dump_data ("RECV", session->incoming_buf, offset);
  761. #endif
  762. // parse the string
  763. libirc_process_incoming_data (session, offset);
  764. offset = libirc_findcrlf_offset(session->incoming_buf, offset, session->incoming_offset);
  765. if ( session->incoming_offset - offset > 0 )
  766. memmove (session->incoming_buf, session->incoming_buf + offset, session->incoming_offset - offset);
  767. session->incoming_offset -= offset;
  768. }
  769. }
  770. // We can write a stored buffer
  771. if ( FD_ISSET (session->sock, out_set) )
  772. {
  773. int length;
  774. // Because outgoing_buf could be changed asynchronously, we should lock any change
  775. libirc_mutex_lock (&session->mutex_session);
  776. length = session_socket_write( session );
  777. if ( length < 0 )
  778. {
  779. if ( session->lasterror == 0 )
  780. session->lasterror = (length == 0 ? LIBIRC_ERR_CLOSED : LIBIRC_ERR_TERMINATED);
  781. session->state = LIBIRC_STATE_DISCONNECTED;
  782. libirc_mutex_unlock (&session->mutex_session);
  783. return 1;
  784. }
  785. #if defined (ENABLE_DEBUG)
  786. if ( IS_DEBUG_ENABLED(session) )
  787. libirc_dump_data ("SEND", session->outgoing_buf, length);
  788. #endif
  789. if ( length > 0 && session->outgoing_offset - length > 0 )
  790. memmove (session->outgoing_buf, session->outgoing_buf + length, session->outgoing_offset - length);
  791. session->outgoing_offset -= length;
  792. libirc_mutex_unlock (&session->mutex_session);
  793. }
  794. return 0;
  795. }
  796. int irc_send_raw (irc_session_t * session, const char * format, ...)
  797. {
  798. char buf[1024];
  799. va_list va_alist;
  800. if ( session->state != LIBIRC_STATE_CONNECTED )
  801. {
  802. session->lasterror = LIBIRC_ERR_STATE;
  803. return 1;
  804. }
  805. va_start (va_alist, format);
  806. vsnprintf (buf, sizeof(buf), format, va_alist);
  807. va_end (va_alist);
  808. libirc_mutex_lock (&session->mutex_session);
  809. if ( (strlen(buf) + 2) >= (sizeof(session->outgoing_buf) - session->outgoing_offset) )
  810. {
  811. libirc_mutex_unlock (&session->mutex_session);
  812. session->lasterror = LIBIRC_ERR_NOMEM;
  813. return 1;
  814. }
  815. strcpy (session->outgoing_buf + session->outgoing_offset, buf);
  816. session->outgoing_offset += strlen (buf);
  817. session->outgoing_buf[session->outgoing_offset++] = 0x0D;
  818. session->outgoing_buf[session->outgoing_offset++] = 0x0A;
  819. libirc_mutex_unlock (&session->mutex_session);
  820. return 0;
  821. }
  822. int irc_cmd_quit (irc_session_t * session, const char * reason)
  823. {
  824. return irc_send_raw (session, "QUIT :%s", reason ? reason : "quit");
  825. }
  826. int irc_cmd_join (irc_session_t * session, const char * channel, const char * key)
  827. {
  828. if ( !channel )
  829. {
  830. session->lasterror = LIBIRC_ERR_STATE;
  831. return 1;
  832. }
  833. if ( key )
  834. return irc_send_raw (session, "JOIN %s :%s", channel, key);
  835. else
  836. return irc_send_raw (session, "JOIN %s", channel);
  837. }
  838. int irc_cmd_part (irc_session_t * session, const char * channel)
  839. {
  840. if ( !channel )
  841. {
  842. session->lasterror = LIBIRC_ERR_STATE;
  843. return 1;
  844. }
  845. return irc_send_raw (session, "PART %s", channel);
  846. }
  847. int irc_cmd_topic (irc_session_t * session, const char * channel, const char * topic)
  848. {
  849. if ( !channel )
  850. {
  851. session->lasterror = LIBIRC_ERR_STATE;
  852. return 1;
  853. }
  854. if ( topic )
  855. return irc_send_raw (session, "TOPIC %s :%s", channel, topic);
  856. else
  857. return irc_send_raw (session, "TOPIC %s", channel);
  858. }
  859. int irc_cmd_names (irc_session_t * session, const char * channel)
  860. {
  861. if ( !channel )
  862. {
  863. session->lasterror = LIBIRC_ERR_STATE;
  864. return 1;
  865. }
  866. return irc_send_raw (session, "NAMES %s", channel);
  867. }
  868. int irc_cmd_list (irc_session_t * session, const char * channel)
  869. {
  870. if ( channel )
  871. return irc_send_raw (session, "LIST %s", channel);
  872. else
  873. return irc_send_raw (session, "LIST");
  874. }
  875. int irc_cmd_invite (irc_session_t * session, const char * nick, const char * channel)
  876. {
  877. if ( !channel || !nick )
  878. {
  879. session->lasterror = LIBIRC_ERR_STATE;
  880. return 1;
  881. }
  882. return irc_send_raw (session, "INVITE %s %s", nick, channel);
  883. }
  884. int irc_cmd_kick (irc_session_t * session, const char * nick, const char * channel, const char * comment)
  885. {
  886. if ( !channel || !nick )
  887. {
  888. session->lasterror = LIBIRC_ERR_STATE;
  889. return 1;
  890. }
  891. if ( comment )
  892. return irc_send_raw (session, "KICK %s %s :%s", channel, nick, comment);
  893. else
  894. return irc_send_raw (session, "KICK %s %s", channel, nick);
  895. }
  896. int irc_cmd_msg (irc_session_t * session, const char * nch, const char * text)
  897. {
  898. if ( !nch || !text )
  899. {
  900. session->lasterror = LIBIRC_ERR_STATE;
  901. return 1;
  902. }
  903. return irc_send_raw (session, "PRIVMSG %s :%s", nch, text);
  904. }
  905. int irc_cmd_notice (irc_session_t * session, const char * nch, const char * text)
  906. {
  907. if ( !nch || !text )
  908. {
  909. session->lasterror = LIBIRC_ERR_STATE;
  910. return 1;
  911. }
  912. return irc_send_raw (session, "NOTICE %s :%s", nch, text);
  913. }
  914. void irc_target_get_nick (const char * target, char *nick, size_t size)
  915. {
  916. char *p = strstr (target, "!");
  917. unsigned int len;
  918. if ( p )
  919. len = p - target;
  920. else
  921. len = strlen (target);
  922. if ( len > size-1 )
  923. len = size - 1;
  924. memcpy (nick, target, len);
  925. nick[len] = '\0';
  926. }
  927. void irc_target_get_host (const char * target, char *host, size_t size)
  928. {
  929. unsigned int len;
  930. const char *p = strstr (target, "!");
  931. if ( !p )
  932. p = target;
  933. len = strlen (p);
  934. if ( len > size-1 )
  935. len = size - 1;
  936. memcpy (host, p, len);
  937. host[len] = '\0';
  938. }
  939. int irc_cmd_ctcp_request (irc_session_t * session, const char * nick, const char * reply)
  940. {
  941. if ( !nick || !reply )
  942. {
  943. session->lasterror = LIBIRC_ERR_STATE;
  944. return 1;
  945. }
  946. return irc_send_raw (session, "PRIVMSG %s :\x01%s\x01", nick, reply);
  947. }
  948. int irc_cmd_ctcp_reply (irc_session_t * session, const char * nick, const char * reply)
  949. {
  950. if ( !nick || !reply )
  951. {
  952. session->lasterror = LIBIRC_ERR_STATE;
  953. return 1;
  954. }
  955. return irc_send_raw (session, "NOTICE %s :\x01%s\x01", nick, reply);
  956. }
  957. void irc_get_version (unsigned int * high, unsigned int * low)
  958. {
  959. *high = LIBIRC_VERSION_HIGH;
  960. *low = LIBIRC_VERSION_LOW;
  961. }
  962. void irc_set_ctx (irc_session_t * session, void * ctx)
  963. {
  964. session->ctx = ctx;
  965. }
  966. void * irc_get_ctx (irc_session_t * session)
  967. {
  968. return session->ctx;
  969. }
  970. void irc_set_ctcp_version (irc_session_t * session, const char * version)
  971. {
  972. if ( session->ctcp_version )
  973. free(session->ctcp_version);
  974. session->ctcp_version = strdup(version);
  975. }
  976. void irc_disconnect (irc_session_t * session)
  977. {
  978. if ( session->sock >= 0 )
  979. socket_close (&session->sock);
  980. session->sock = -1;
  981. session->state = LIBIRC_STATE_INIT;
  982. }
  983. int irc_cmd_me (irc_session_t * session, const char * nch, const char * text)
  984. {
  985. if ( !nch || !text )
  986. {
  987. session->lasterror = LIBIRC_ERR_STATE;
  988. return 1;
  989. }
  990. return irc_send_raw (session, "PRIVMSG %s :\x01" "ACTION %s\x01", nch, text);
  991. }
  992. void irc_option_set (irc_session_t * session, unsigned int option)
  993. {
  994. session->options |= option;
  995. }
  996. void irc_option_reset (irc_session_t * session, unsigned int option)
  997. {
  998. session->options &= ~option;
  999. }
  1000. int irc_cmd_channel_mode (irc_session_t * session, const char * channel, const char * mode)
  1001. {
  1002. if ( !channel )
  1003. {
  1004. session->lasterror = LIBIRC_ERR_INVAL;
  1005. return 1;
  1006. }
  1007. if ( mode )
  1008. return irc_send_raw (session, "MODE %s %s", channel, mode);
  1009. else
  1010. return irc_send_raw (session, "MODE %s", channel);
  1011. }
  1012. int irc_cmd_user_mode (irc_session_t * session, const char * mode)
  1013. {
  1014. if ( mode )
  1015. return irc_send_raw (session, "MODE %s %s", session->nick, mode);
  1016. else
  1017. return irc_send_raw (session, "MODE %s", session->nick);
  1018. }
  1019. int irc_cmd_nick (irc_session_t * session, const char * newnick)
  1020. {
  1021. if ( !newnick )
  1022. {
  1023. session->lasterror = LIBIRC_ERR_INVAL;
  1024. return 1;
  1025. }
  1026. return irc_send_raw (session, "NICK %s", newnick);
  1027. }
  1028. int irc_cmd_whois (irc_session_t * session, const char * nick)
  1029. {
  1030. if ( !nick )
  1031. {
  1032. session->lasterror = LIBIRC_ERR_INVAL;
  1033. return 1;
  1034. }
  1035. return irc_send_raw (session, "WHOIS %s %s", nick, nick);
  1036. }