#include #include #include #include #include #include #include #include #include #include "irc.h" int IRCC_urecv(IRCC_client *irc) { #ifdef ENABLE_SSL if (irc->irc_usingssl) return SSL_read(irc->irc_ssl, irc->irc_raw, sizeof(irc->irc_raw)); #endif return recv(irc->irc_socket, irc->irc_raw, sizeof(irc->irc_raw), 0); } int IRCC_usend(IRCC_client *irc, off_t bytes) { #ifdef ENABLE_SSL if (irc->irc_usingssl) return SSL_write(irc->irc_ssl, irc->irc_raw, bytes); #endif return send(irc->irc_socket, irc->irc_raw, bytes, 0); } int IRCC_connect(IRCC_client *irc, const char *ip, const unsigned int port) { struct hostent *hp = gethostbyname(ip); if (!hp) return IRCC_ERROR; //Only ipv4 struct sockaddr_in client_str; memset(&client_str, 0, sizeof(client_str)); client_str.sin_family = AF_INET; client_str.sin_port = htons(port); client_str.sin_addr.s_addr = inet_addr(inet_ntoa(*(struct in_addr *)hp->h_addr)); irc->irc_socket = socket(AF_INET, SOCK_STREAM, 0); if (irc->irc_socket < 0) return IRCC_ERROR; struct timeval tv = {IRCC_PING_TIMEOUT, 0}; if (setsockopt(irc->irc_socket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) return IRCC_ERROR; int status = connect(irc->irc_socket, (struct sockaddr *)&client_str, sizeof(client_str)); if (status == -1) return IRCC_ERROR; return IRCC_SUCCESS; } void IRCC_parse_msg(char *tmp, IRCC_client *irc) { irc->irc_raw[strcspn(irc->irc_raw, "\r\n")] = '\0'; if (tmp != NULL) { //Message char *val = strchr(tmp, ':'); if (val != NULL) { val[0] = '\0'; irc->irc_msg = val + 1; //Del space before : *(val - 1) = '\0'; } //Channel val = strchr(tmp, ' '); if (val != NULL) { val[0] = '\0'; irc->irc_channel = val + 1; } //Nickname val = strchr(irc->irc_raw, '!'); if (val != NULL) { val[0] = '\0'; irc->irc_nick = irc->irc_raw + 1; } } } int IRCC_recv(IRCC_client *irc) { memset(irc->irc_raw, '\0', IRCC_MSG_MAX); int msg_size = IRCC_urecv(irc); if (msg_size == 0 || msg_size == -1) return IRCC_DISCONNECTED; else if (!strncmp(irc->irc_raw, "PING", 4)) { *(strchr(irc->irc_raw, 'I')) = 'O'; if (IRCC_usend(irc, strlen(irc->irc_raw)) == -1) return IRCC_ERROR; return IRCC_PING; } return IRCC_SUCCESS; } int IRCC_parse(IRCC_client *irc) { irc->irc_channel = NULL; irc->irc_msg = NULL; irc->irc_nick = NULL; //Check end of motd if (strstr(irc->irc_raw, "PRIVMSG ") == NULL && strstr(irc->irc_raw, "MOTD")) return IRCC_CONNECTED; //Other else if (strstr(irc->irc_raw, "PRIVMSG ")) { IRCC_parse_msg(strstr(irc->irc_raw, "PRIVMSG "), irc); return IRCC_PRIVMSG; } else if (strstr(irc->irc_raw, "NICK ")) { IRCC_parse_msg(strstr(irc->irc_raw, "NICK "), irc); return IRCC_NICK; } else if (strstr(irc->irc_raw, "TOPIC ")) { IRCC_parse_msg(strstr(irc->irc_raw, "TOPIC "), irc); return IRCC_TOPIC; } else if (strstr(irc->irc_raw, "MODE ")) { IRCC_parse_msg(strstr(irc->irc_raw, "MODE "), irc); return IRCC_MODE; } else if (strstr(irc->irc_raw, "JOIN ")) { IRCC_parse_msg(strstr(irc->irc_raw, "JOIN "), irc); return IRCC_JOIN; } else if (strstr(irc->irc_raw, "PART ") || strstr(irc->irc_raw, "QUIT ")) { IRCC_parse_msg(strstr(irc->irc_raw, "PART "), irc); IRCC_parse_msg(strstr(irc->irc_raw, "QUIT "), irc); return IRCC_QUIT; } return IRCC_SUCCESS; } int IRCC_register(IRCC_client *irc, const char *nickname) { off_t bytes = snprintf(irc->irc_raw, sizeof(irc->irc_raw), "NICK %s\r\n", nickname); if (IRCC_usend(irc, bytes) == -1) return IRCC_ERROR; bytes = snprintf(irc->irc_raw, sizeof(irc->irc_raw), "USER %s 0 localhost :%s\r\n", nickname, nickname); if (IRCC_usend(irc, bytes) == -1) return IRCC_ERROR; //Motd skip while (1) { int status = IRCC_recv(irc); if (status == IRCC_DISCONNECTED) return IRCC_DISCONNECTED; status = IRCC_parse(irc); if (status == IRCC_CONNECTED) break; } return IRCC_SUCCESS; } int IRCC_join(IRCC_client *irc, const char *channel, const char *key) { off_t bytes = snprintf(irc->irc_raw, sizeof(irc->irc_raw), "JOIN %s %s\r\n", channel, (key) ? key : ""); if (IRCC_usend(irc, bytes) == -1) return IRCC_ERROR; return IRCC_SUCCESS; } int IRCC_send(IRCC_client *irc, const char *channel, const char *msg) { off_t bytes = snprintf(irc->irc_raw, sizeof(irc->irc_raw), "PRIVMSG %s :%s\r\n", channel, msg); if (IRCC_usend(irc, bytes) == -1) return IRCC_ERROR; return IRCC_SUCCESS; } int IRCC_initssl(IRCC_client *irc) { #ifdef ENABLE_SSL irc->irc_ssl = NULL; irc->irc_sslctx = NULL; irc->irc_sslmethod = NULL; OpenSSL_add_all_algorithms(); if (SSL_library_init() < 0) return IRCC_ERROR; irc->irc_sslmethod = (SSL_METHOD *)SSLv23_client_method(); irc->irc_sslctx = SSL_CTX_new(irc->irc_sslmethod); if (irc->irc_sslctx == NULL) return IRCC_ERROR; SSL_CTX_set_options(irc->irc_sslctx, SSL_OP_NO_SSLv2); irc->irc_ssl = SSL_new(irc->irc_sslctx); SSL_set_fd(irc->irc_ssl, irc->irc_socket); if (SSL_connect(irc->irc_ssl) != 1) return IRCC_ERROR; irc->irc_usingssl = 1; #else (void)irc; #endif return IRCC_SUCCESS; } void IRCC_close(IRCC_client *irc) { close(irc->irc_socket); irc->irc_msg = irc->irc_nick = irc->irc_channel = NULL; #ifdef ENABLE_SSL if (!irc->irc_usingssl) return; if (irc->irc_ssl != NULL) { SSL_shutdown(irc->irc_ssl); SSL_free(irc->irc_ssl); } if (irc->irc_sslctx != NULL) SSL_CTX_free(irc->irc_sslctx); #endif }