static void handle_ctcp_request(irc_session_t *session, irc_parser_result_t *result) { char ctcp_buf[LIBIRC_BUFFER_SIZE]; char **params = result->params; size_t msglen = strlen(result->params[1]); msglen -= 2; if (msglen > sizeof (ctcp_buf) - 1) msglen = sizeof (ctcp_buf) - 1; memcpy(ctcp_buf, params[1] + 1, msglen); ctcp_buf[msglen] = '\0'; DBG_OK("ctcp req recvd! %s", ctcp_buf); if (is_dcc_request(ctcp_buf)) { libirc_dcc_request(session, result, ctcp_buf); } else if (is_action_message(ctcp_buf) && session->callbacks.event_ctcp_action) { // this removes "ACTION" in front of the message char *buf = calloc(strlen(ctcp_buf)+1, sizeof(char)); memcpy(buf, ctcp_buf+7, strlen(ctcp_buf)-7); params[1] = buf; result->num_params = 2; (*session->callbacks.event_ctcp_action) (session, "ACTION", result); } else { char *buf = calloc(strlen(ctcp_buf)+1, sizeof(char)); memcpy(buf, ctcp_buf, strlen(ctcp_buf)); params[0] = buf; result->num_params = 1; if (session->callbacks.event_ctcp_req) (*session->callbacks.event_ctcp_req) (session, "CTCP", result); } }
static void libirc_process_incoming_data (irc_session_t * session, int process_length) { #define MAX_PARAMS_ALLOWED 10 char buf[2*512], *p, *s; const char * command = 0, *prefix = 0, *params[MAX_PARAMS_ALLOWED+1]; int code = 0, paramindex = 0; if ( process_length > (int)sizeof(buf) ) abort(); // should be impossible memcpy (buf, session->incoming_buf, process_length); buf[process_length] = '\0'; memset (params, 0, sizeof(params)); p = buf; /* * From RFC 1459: * <message> ::= [':' <prefix> <SPACE> ] <command> <params> <crlf> * <prefix> ::= <servername> | <nick> [ '!' <user> ] [ '@' <host> ] * <command> ::= <letter> { <letter> } | <number> <number> <number> * <SPACE> ::= ' ' { ' ' } * <params> ::= <SPACE> [ ':' <trailing> | <middle> <params> ] * <middle> ::= <Any *non-empty* sequence of octets not including SPACE * or NUL or CR or LF, the first of which may not be ':'> * <trailing> ::= <Any, possibly *empty*, sequence of octets not including * NUL or CR or LF> */ // Parse <prefix> if ( buf[0] == ':' ) { while ( *p && *p != ' ') p++; *p++ = '\0'; // we use buf+1 to skip the leading colon prefix = buf + 1; // If LIBIRC_OPTION_STRIPNICKS is set, we should 'clean up' nick // right here if ( session->options & LIBIRC_OPTION_STRIPNICKS ) { for ( s = buf + 1; *s; ++s ) { if ( *s == '@' || *s == '!' ) { *s = '\0'; break; } } } } // Parse <command> if ( isdigit (p[0]) && isdigit (p[1]) && isdigit (p[2]) ) { p[3] = '\0'; code = atoi (p); p += 4; } else { s = p; while ( *p && *p != ' ') ++p; *p++ = '\0'; command = s; } // Parse middle/params while ( *p && paramindex < MAX_PARAMS_ALLOWED ) { // beginning from ':', this is the last param if ( *p == ':' ) { params[paramindex++] = p + 1; // skip : break; } // Just a param for ( s = p; *p && *p != ' '; ++p ) ; params[paramindex++] = s; if ( !*p ) break; *p++ = '\0'; } // Handle PING/PONG if ( command && !strcmp (command, "PING") && params[0] ) { irc_send_raw (session, "PONG %s", params[0]); return; } // and dump if ( code ) { // We use session->motd_received to check whether it is the first // RPL_ENDOFMOTD or ERR_NOMOTD after the connection. if ( (code == 376 || code == 422) && !session->motd_received ) { session->motd_received = 1; if ( session->callbacks.event_connect ) (*session->callbacks.event_connect) (session, "CONNECT", prefix, params, paramindex); } if ( session->callbacks.event_numeric ) (*session->callbacks.event_numeric) (session, code, prefix, params, paramindex); } else { if ( !strcmp (command, "NICK") ) { /* * If we're changed our nick, we should save it. */ char nickbuf[256]; irc_target_get_nick (prefix, nickbuf, sizeof(nickbuf)); if ( !strcmp (nickbuf, session->nick) && paramindex > 0 ) { free (session->nick); session->nick = strdup (params[0]); } if ( session->callbacks.event_nick ) (*session->callbacks.event_nick) (session, command, prefix, params, paramindex); } else if ( !strcmp (command, "QUIT") ) { if ( session->callbacks.event_quit ) (*session->callbacks.event_quit) (session, command, prefix, params, paramindex); } else if ( !strcmp (command, "JOIN") ) { if ( session->callbacks.event_join ) (*session->callbacks.event_join) (session, command, prefix, params, paramindex); } else if ( !strcmp (command, "PART") ) { if ( session->callbacks.event_part ) (*session->callbacks.event_part) (session, command, prefix, params, paramindex); } else if ( !strcmp (command, "MODE") ) { if ( paramindex > 0 && !strcmp (params[0], session->nick) ) { params[0] = params[1]; paramindex = 1; if ( session->callbacks.event_umode ) (*session->callbacks.event_umode) (session, command, prefix, params, paramindex); } else { if ( session->callbacks.event_mode ) (*session->callbacks.event_mode) (session, command, prefix, params, paramindex); } } else if ( !strcmp (command, "TOPIC") ) { if ( session->callbacks.event_topic ) (*session->callbacks.event_topic) (session, command, prefix, params, paramindex); } else if ( !strcmp (command, "KICK") ) { if ( session->callbacks.event_kick ) (*session->callbacks.event_kick) (session, command, prefix, params, paramindex); } else if ( !strcmp (command, "PRIVMSG") ) { if ( paramindex > 1 ) { unsigned int msglen = strlen (params[1]); /* * Check for CTCP request (a CTCP message starts from 0x01 * and ends by 0x01 */ if ( params[1][0] == 0x01 && params[1][msglen-1] == 0x01 ) { char ctcp_buf[ 128 ]; memset( ctcp_buf, 0, 128 ); msglen -= 2; if ( msglen > sizeof(ctcp_buf) - 1 ) msglen = sizeof(ctcp_buf) - 1; memcpy (ctcp_buf, params[1] + 1, msglen); ctcp_buf[msglen] = '\0'; if ( strstr(ctcp_buf, "DCC ") == ctcp_buf ) libirc_dcc_request (session, prefix, ctcp_buf); else if ( strstr(ctcp_buf, "ACTION ") == ctcp_buf && session->callbacks.event_ctcp_action ) { params[0] = ctcp_buf + 7; // the length of "ACTION " paramindex = 1; (*session->callbacks.event_ctcp_action) (session, "ACTION", prefix, params, paramindex); } else { params[0] = ctcp_buf; paramindex = 1; if ( session->callbacks.event_ctcp_req ) (*session->callbacks.event_ctcp_req) (session, "CTCP", prefix, params, paramindex); } } else if ( !strcmp (params[0], session->nick) ) { if ( session->callbacks.event_privmsg ) (*session->callbacks.event_privmsg) (session, command, prefix, params, paramindex); } else { if ( session->callbacks.event_channel ) (*session->callbacks.event_channel) (session, command, prefix, params, paramindex); } } } else if ( !strcmp (command, "NOTICE") ) { unsigned int msglen = strlen (params[1]); /* * Check for CTCP request (a CTCP message starts from 0x01 * and ends by 0x01 */ if ( paramindex > 1 && params[1][0] == 0x01 && params[1][msglen-1] == 0x01 ) { char ctcp_buf[512]; msglen -= 2; if ( msglen > sizeof(ctcp_buf) - 1 ) msglen = sizeof(ctcp_buf) - 1; memcpy (ctcp_buf, params[1] + 1, msglen); ctcp_buf[msglen] = '\0'; params[0] = ctcp_buf; paramindex = 1; if ( session->callbacks.event_ctcp_rep ) (*session->callbacks.event_ctcp_rep) (session, "CTCP", prefix, params, paramindex); } else { if ( session->callbacks.event_notice ) (*session->callbacks.event_notice) (session, command, prefix, params, paramindex); } } else if ( !strcmp (command, "INVITE") ) { if ( session->callbacks.event_invite ) (*session->callbacks.event_invite) (session, command, prefix, params, paramindex); } else if ( !strcmp (command, "KILL") ) { ; /* ignore this event - not all servers generate this */ } else { /* * The "unknown" event is triggered upon receipt of any number of * unclassifiable miscellaneous messages, which aren't handled by * the library. */ if ( session->callbacks.event_unknown ) (*session->callbacks.event_unknown) (session, command, prefix, params, paramindex); } } }