From 17dec0f70d683ffe217173f9de4ad2a92128487c Mon Sep 17 00:00:00 2001 From: Kelly Rauchenberger Date: Sat, 10 Aug 2013 12:50:50 -0400 Subject: first commit --- IRC.cc | 877 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ IRC.h | 101 ++++++++ main.cpp | 81 ++++++ 3 files changed, 1059 insertions(+) create mode 100755 IRC.cc create mode 100755 IRC.h create mode 100644 main.cpp diff --git a/IRC.cc b/IRC.cc new file mode 100755 index 0000000..b6b4da4 --- /dev/null +++ b/IRC.cc @@ -0,0 +1,877 @@ +/* + cpIRC - C++ class based IRC protocol wrapper + Copyright (C) 2003 Iain Sheppard + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Contacting the author: + ~~~~~~~~~~~~~~~~~~~~~~ + + email: iainsheppard@yahoo.co.uk + IRC: #magpie @ irc.quakenet.org +*/ + +#include "IRC.h" +#ifdef WIN32 +#include +#else +#include +#include +#include +#include +#include +#include +#include +#include +#define closesocket(s) close(s) +#define SOCKET_ERROR -1 +#define INVALID_SOCKET -1 +#endif + +IRC::IRC() +{ + hooks=0; + chan_users=0; + connected=false; + sentnick=false; + sentpass=false; + sentuser=false; + cur_nick=0; +} + +IRC::~IRC() +{ + if (hooks) + delete_irc_command_hook(hooks); +} + +void IRC::insert_irc_command_hook(irc_command_hook* hook, char* cmd_name, int (*function_ptr)(char*, irc_reply_data*, void*)) +{ + if (hook->function) + { + if (!hook->next) + { + hook->next=new irc_command_hook; + hook->next->function=0; + hook->next->irc_command=0; + hook->next->next=0; + } + insert_irc_command_hook(hook->next, cmd_name, function_ptr); + } + else + { + hook->function=function_ptr; + hook->irc_command=new char[strlen(cmd_name)+1]; + strcpy(hook->irc_command, cmd_name); + } +} + +void IRC::hook_irc_command(char* cmd_name, int (*function_ptr)(char*, irc_reply_data*, void*)) +{ + if (!hooks) + { + hooks=new irc_command_hook; + hooks->function=0; + hooks->irc_command=0; + hooks->next=0; + insert_irc_command_hook(hooks, cmd_name, function_ptr); + } + else + { + insert_irc_command_hook(hooks, cmd_name, function_ptr); + } +} + +void IRC::delete_irc_command_hook(irc_command_hook* cmd_hook) +{ + if (cmd_hook->next) + delete_irc_command_hook(cmd_hook->next); + if (cmd_hook->irc_command) + delete cmd_hook->irc_command; + delete cmd_hook; +} + +int IRC::start(char* server, int port, char* nick, char* user, char* name, char* pass) +{ + #ifdef WIN32 + HOSTENT* resolv; + #else + hostent* resolv; + #endif + sockaddr_in rem; + + if (connected) + return 1; + + irc_socket=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (irc_socket==INVALID_SOCKET) + { + return 1; + } + resolv=gethostbyname(server); + if (!resolv) + { + closesocket(irc_socket); + return 1; + } + memcpy(&rem.sin_addr, resolv->h_addr, 4); + rem.sin_family=AF_INET; + rem.sin_port=htons(port); + + if (connect(irc_socket, (const sockaddr*)&rem, sizeof(rem))==SOCKET_ERROR) + { + #ifdef WIN32 + printf("Failed to connect: %d\n", WSAGetLastError()); + #endif + closesocket(irc_socket); + return 1; + } + + dataout=fdopen(irc_socket, "w"); + //datain=fdopen(irc_socket, "r"); + + if (!dataout /*|| !datain*/) + { + printf("Failed to open streams!\n"); + closesocket(irc_socket); + return 1; + } + + connected=true; + + cur_nick=new char[strlen(nick)+1]; + strcpy(cur_nick, nick); + + fprintf(dataout, "PASS %s\r\n", pass); + fprintf(dataout, "NICK %s\r\n", nick); + fprintf(dataout, "USER %s * 0 :%s\r\n", user, name); + fflush(dataout); + + return 0; +} + +void IRC::disconnect() +{ + if (connected) + { + fclose(dataout); + printf("Disconnected from server.\n"); + connected=false; + quit("Leaving"); + #ifdef WIN32 + shutdown(irc_socket, 2); + #endif + closesocket(irc_socket); + } +} + +int IRC::quit(char* quit_message) +{ + if (connected) + { + if (quit_message) + fprintf(dataout, "QUIT %s\r\n", quit_message); + else + fprintf(dataout, "QUIT\r\n"); + if (fflush(dataout)) + return 1; + } + return 0; +} + +int IRC::message_loop() +{ + char buffer[1024]; + int ret_len; + + if (!connected) + { + printf("Not connected!\n"); + return 1; + } + + while (1) + { + ret_len=recv(irc_socket, buffer, 1023, 0); + if (ret_len==SOCKET_ERROR || !ret_len) + { + return 1; + } + buffer[ret_len]='\0'; + split_to_replies(buffer); + } + + return 0; +} + +void IRC::split_to_replies(char* data) +{ + char* p; + + while (p=strstr(data, "\r\n")) + { + *p='\0'; + parse_irc_reply(data); + data=p+2; + } +} + +int IRC::is_op(char* channel, char* nick) +{ + channel_user* cup; + + cup=chan_users; + + while (cup) + { + if (!strcmp(cup->channel, channel) && !strcmp(cup->nick, nick)) + { + return cup->flags&IRC_USER_OP; + } + cup=cup->next; + } + + return 0; +} + +int IRC::is_voice(char* channel, char* nick) +{ + channel_user* cup; + + cup=chan_users; + + while (cup) + { + if (!strcmp(cup->channel, channel) && !strcmp(cup->nick, nick)) + { + return cup->flags&IRC_USER_VOICE; + } + cup=cup->next; + } + + return 0; +} + +void IRC::parse_irc_reply(char* data) +{ + char* hostd; + char* cmd; + char* params; + char buffer[514]; + irc_reply_data hostd_tmp; + channel_user* cup; + char* p; + char* chan_temp; + + hostd_tmp.target=0; + + printf("%s\n", data); + + if (data[0]==':') + { + hostd=&data[1]; + cmd=strchr(hostd, ' '); + if (!cmd) + return; + *cmd='\0'; + cmd++; + params=strchr(cmd, ' '); + if (params) + { + *params='\0'; + params++; + } + if (params[0]==':') + { + *params='\0'; + params++; + } + hostd_tmp.nick=hostd; + hostd_tmp.ident=strchr(hostd, '!'); + if (hostd_tmp.ident) + { + *hostd_tmp.ident='\0'; + hostd_tmp.ident++; + hostd_tmp.host=strchr(hostd_tmp.ident, '@'); + if (hostd_tmp.host) + { + *hostd_tmp.host='\0'; + hostd_tmp.host++; + } + } + + if (!strcmp(cmd, "JOIN")) + { + + + cup=chan_users; + if (cup) + { + while (cup->nick) + { + if (!cup->next) + { + cup->next=new channel_user; + cup->next->channel=0; + cup->next->flags=0; + cup->next->next=0; + cup->next->nick=0; + } + cup=cup->next; + } + cup->channel=new char[strlen(params)+1]; + strcpy(cup->channel, params); + cup->nick=new char[strlen(hostd_tmp.nick)+1]; + strcpy(cup->nick, hostd_tmp.nick); + } + } + else if (!strcmp(cmd, "PART")) + { + channel_user* d; + channel_user* prev; + + d=0; + prev=0; + cup=chan_users; + while (cup) + { + if (!strcmp(cup->channel, params) && !strcmp(cup->nick, hostd_tmp.nick)) + { + d=cup; + break; + } + else + { + prev=cup; + } + cup=cup->next; + } + if (d) + { + if (d==chan_users) + { + chan_users=d->next; + if (d->channel) + delete [] d->channel; + if (d->nick) + delete [] d->nick; + delete d; + } + else + { + if (prev) + { + prev->next=d->next; + } + chan_users=d->next; + if (d->channel) + delete [] d->channel; + if (d->nick) + delete [] d->nick; + delete d; + } + } + } + else if (!strcmp(cmd, "QUIT")) + { + channel_user* d; + channel_user* prev; + + d=0; + prev=0; + cup=chan_users; + while (cup) + { + if (!strcmp(cup->nick, hostd_tmp.nick)) + { + d=cup; + if (d==chan_users) + { + chan_users=d->next; + if (d->channel) + delete [] d->channel; + if (d->nick) + delete [] d->nick; + delete d; + } + else + { + if (prev) + { + prev->next=d->next; + } + if (d->channel) + delete [] d->channel; + if (d->nick) + delete [] d->nick; + delete d; + } + break; + } + else + { + prev=cup; + } + cup=cup->next; + } + } + else if (!strcmp(cmd, "MODE")) + { + char* chan; + char* changevars; + channel_user* cup; + channel_user* d; + char* tmp; + int i; + bool plus; + + chan=params; + params=strchr(chan, ' '); + *params='\0'; + params++; + changevars=params; + params=strchr(changevars, ' '); + if (!params) + { + return; + } + if (chan[0]!='#') + { + return; + } + *params='\0'; + params++; + + plus=false; + for (i=0; i<(signed)strlen(changevars); i++) + { + switch (changevars[i]) + { + case '+': + plus=true; + break; + case '-': + plus=false; + break; + case 'q': + break; + case 'o': + tmp=strchr(params, ' '); + if (tmp) + { + *tmp='\0'; + tmp++; + } + tmp=params; + if (plus) + { + // user has been opped (chan, params) + cup=chan_users; + d=0; + while (cup) + { + if (!strcmp(cup->channel, chan) && !strcmp(cup->nick, tmp)) + { + d=cup; + break; + } + cup=cup->next; + } + if (d) + { + d->flags=d->flags|IRC_USER_OP; + printf("MODE FOR %s ON %s IS %d\n", tmp, chan, d->flags); + } + } + else + { + // user has been deopped (chan, params) + cup=chan_users; + d=0; + while (cup) + { + if (!strcmp(cup->channel, chan) && !strcmp(cup->nick, tmp)) + { + d=cup; + break; + } + cup=cup->next; + } + if (d) + { + d->flags=d->flags^IRC_USER_OP; + } + } + params=tmp; + break; + case 'v': + tmp=strchr(params, ' '); + if (tmp) + { + *tmp='\0'; + tmp++; + } + tmp=params; + if (plus) + { + // user has been voiced + cup=chan_users; + d=0; + while (cup) + { + if (!strcmp(cup->channel, params) && !strcmp(cup->nick, hostd_tmp.nick)) + { + d=cup; + break; + } + cup=cup->next; + } + if (d) + { + d->flags=d->flags|IRC_USER_VOICE; + } + } + else + { + // user has been devoiced + cup=chan_users; + d=0; + while (cup) + { + if (!strcmp(cup->channel, params) && !strcmp(cup->nick, hostd_tmp.nick)) + { + d=cup; + break; + } + cup=cup->next; + } + if (d) + { + d->flags=d->flags^IRC_USER_VOICE; + } + } + params=tmp; + break; + default: + return; + break; + } + // ------------ END OF MODE --------------- + } + } + else if (!strcmp(cmd, "353")) + { + // receiving channel names list + if (!chan_users) + { + chan_users=new channel_user; + chan_users->next=0; + chan_users->nick=0; + chan_users->flags=0; + chan_users->channel=0; + } + cup=chan_users; + chan_temp=strchr(params, '#'); + if (chan_temp) + { + //chan_temp+=3; + p=strstr(chan_temp, " :"); + if (p) + { + *p='\0'; + p+=2; + while (strchr(p, ' ')) + { + char* tmp; + + tmp=strchr(p, ' '); + *tmp='\0'; + tmp++; + while (cup->nick) + { + if (!cup->next) + { + cup->next=new channel_user; + cup->next->channel=0; + cup->next->flags=0; + cup->next->next=0; + cup->next->nick=0; + } + cup=cup->next; + } + if (p[0]=='@') + { + cup->flags=cup->flags|IRC_USER_OP; + p++; + } + else if (p[0]=='+') + { + cup->flags=cup->flags|IRC_USER_VOICE; + p++; + } + cup->nick=new char[strlen(p)+1]; + strcpy(cup->nick, p); + cup->channel=new char[strlen(chan_temp)+1]; + strcpy(cup->channel, chan_temp); + p=tmp; + } + while (cup->nick) + { + if (!cup->next) + { + cup->next=new channel_user; + cup->next->channel=0; + cup->next->flags=0; + cup->next->next=0; + cup->next->nick=0; + } + cup=cup->next; + } + if (p[0]=='@') + { + cup->flags=cup->flags|IRC_USER_OP; + p++; + } + else if (p[0]=='+') + { + cup->flags=cup->flags|IRC_USER_VOICE; + p++; + } + cup->nick=new char[strlen(p)+1]; + strcpy(cup->nick, p); + cup->channel=new char[strlen(chan_temp)+1]; + strcpy(cup->channel, chan_temp); + } + } + } + else if (!strcmp(cmd, "NOTICE")) + { + hostd_tmp.target=params; + params=strchr(hostd_tmp.target, ' '); + if (params) + *params='\0'; + params++; + #ifdef __IRC_DEBUG__ + printf("%s >-%s- %s\n", hostd_tmp.nick, hostd_tmp.target, ¶ms[1]); + #endif + } + else if (!strcmp(cmd, "PRIVMSG")) + { + hostd_tmp.target=params; + params=strchr(hostd_tmp.target, ' '); + if (!params) + return; + *(params++)='\0'; + #ifdef __IRC_DEBUG__ + printf("%s: <%s> %s\n", hostd_tmp.target, hostd_tmp.nick, ¶ms[1]); + #endif + } + else if (!strcmp(cmd, "NICK")) + { + if (!strcmp(hostd_tmp.nick, cur_nick)) + { + delete [] cur_nick; + cur_nick=new char[strlen(params)+1]; + strcpy(cur_nick, params); + } + + cup=chan_users; + while (cup) + { + if (!strcmp(cup->nick, hostd_tmp.nick)) + { + cup->nick=new char[strlen(params)+1]; + strcpy(cup->nick, params); + } + cup=cup->next; + } + } + /* else if (!strcmp(cmd, "")) + { + #ifdef __IRC_DEBUG__ + #endif + } */ + call_hook(cmd, params, &hostd_tmp); + } + else + { + cmd=data; + data=strchr(cmd, ' '); + if (!data) + return; + *data='\0'; + params=data+1; + + if (!strcmp(cmd, "PING")) + { + if (!params) + return; + fprintf(dataout, "PONG %s\r\n", ¶ms[1]); + #ifdef __IRC_DEBUG__ + printf("Ping received, pong sent.\n"); + #endif + fflush(dataout); + } + else + { + hostd_tmp.host=0; + hostd_tmp.ident=0; + hostd_tmp.nick=0; + hostd_tmp.target=0; + call_hook(cmd, params, &hostd_tmp); + } + } +} + +void IRC::call_hook(char* irc_command, char* params, irc_reply_data* hostd) +{ + irc_command_hook* p; + + if (!hooks) + return; + + p=hooks; + while (p) + { + if (!strcmp(p->irc_command, irc_command)) + { + (*(p->function))(params, hostd, this); + p=0; + } + else + { + p=p->next; + } + } +} + +int IRC::notice(char* target, char* message) +{ + if (!connected) + return 1; + fprintf(dataout, "NOTICE %s :%s\r\n", target, message); + return fflush(dataout); +} + +int IRC::notice(char* fmt, ...) +{ + va_list argp; + char* target; + + if (!connected) + return 1; + va_start(argp, fmt); + fprintf(dataout, "NOTICE %s :", fmt); + vfprintf(dataout, va_arg(argp, char*), argp); + va_end(argp); + fprintf(dataout, "\r\n"); + return fflush(dataout); +} + +int IRC::privmsg(char* target, char* message) +{ + if (!connected) + return 1; + fprintf(dataout, "PRIVMSG %s :%s\r\n", target, message); + return fflush(dataout); +} + +int IRC::privmsg(char* fmt, ...) +{ + va_list argp; + char* target; + + if (!connected) + return 1; + va_start(argp, fmt); + fprintf(dataout, "PRIVMSG %s :", fmt); + vfprintf(dataout, va_arg(argp, char*), argp); + va_end(argp); + fprintf(dataout, "\r\n"); + return fflush(dataout); +} + + +int IRC::join(char* channel) +{ + if (!connected) + return 1; + fprintf(dataout, "JOIN %s\r\n", channel); + return fflush(dataout); +} + +int IRC::part(char* channel) +{ + if (!connected) + return 1; + fprintf(dataout, "PART %s\r\n", channel); + return fflush(dataout); +} + +int IRC::kick(char* channel, char* nick) +{ + if (!connected) + return 1; + fprintf(dataout, "KICK %s %s\r\n", channel, nick); + return fflush(dataout); +} + +int IRC::raw(char* data) +{ + if (!connected) + return 1; + fprintf(dataout, "%s\r\n", data); + return fflush(dataout); +} + +int IRC::kick(char* channel, char* nick, char* message) +{ + if (!connected) + return 1; + fprintf(dataout, "KICK %s %s :%s\r\n", channel, nick, message); + return fflush(dataout); +} + +int IRC::mode(char* channel, char* modes, char* targets) +{ + if (!connected) + return 1; + if (!targets) + fprintf(dataout, "MODE %s %s\r\n", channel, modes); + else + fprintf(dataout, "MODE %s %s %s\r\n", channel, modes, targets); + return fflush(dataout); +} + +int IRC::mode(char* modes) +{ + if (!connected) + return 1; + mode(cur_nick, modes, 0); + return 0; +} + +int IRC::nick(char* newnick) +{ + if (!connected) + return 1; + fprintf(dataout, "NICK %s\r\n", newnick); + return fflush(dataout); +} + +char* IRC::current_nick() +{ + return cur_nick; +} diff --git a/IRC.h b/IRC.h new file mode 100755 index 0000000..09df766 --- /dev/null +++ b/IRC.h @@ -0,0 +1,101 @@ +/* + cpIRC - C++ class based IRC protocol wrapper + Copyright (C) 2003 Iain Sheppard + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Contacting the author: + ~~~~~~~~~~~~~~~~~~~~~~ + + email: iainsheppard@yahoo.co.uk + IRC: #magpie @ irc.quakenet.org +*/ + +#include +#include + +#define __CPIRC_VERSION__ 0.1 +#define __IRC_DEBUG__ 1 + +#define IRC_USER_VOICE 1 +#define IRC_USER_HALFOP 2 +#define IRC_USER_OP 4 + +struct irc_reply_data +{ + char* nick; + char* ident; + char* host; + char* target; +}; + +struct irc_command_hook +{ + char* irc_command; + int (*function)(char*, irc_reply_data*, void*); + irc_command_hook* next; +}; + +struct channel_user +{ + char* nick; + char* channel; + char flags; + channel_user* next; +}; + +class IRC +{ +public: + IRC(); + ~IRC(); + int start(char* server, int port, char* nick, char* user, char* name, char* pass); + void disconnect(); + int privmsg(char* target, char* message); + int privmsg(char* fmt, ...); + int notice(char* target, char* message); + int notice(char* fmt, ...); + int join(char* channel); + int part(char* channel); + int kick(char* channel, char* nick); + int kick(char* channel, char* nick, char* message); + int mode(char* modes); + int mode(char* channel, char* modes, char* targets); + int nick(char* newnick); + int quit(char* quit_message); + int raw(char* data); + void hook_irc_command(char* cmd_name, int (*function_ptr)(char*, irc_reply_data*, void*)); + int message_loop(); + int is_op(char* channel, char* nick); + int is_voice(char* channel, char* nick); + char* current_nick(); +private: + void call_hook(char* irc_command, char*params, irc_reply_data* hostd); + /*void call_the_hook(irc_command_hook* hook, char* irc_command, char*params, irc_host_data* hostd);*/ + void parse_irc_reply(char* data); + void split_to_replies(char* data); + void insert_irc_command_hook(irc_command_hook* hook, char* cmd_name, int (*function_ptr)(char*, irc_reply_data*, void*)); + void delete_irc_command_hook(irc_command_hook* cmd_hook); + int irc_socket; + bool connected; + bool sentnick; + bool sentpass; + bool sentuser; + char* cur_nick; + FILE* dataout; + FILE* datain; + channel_user* chan_users; + irc_command_hook* hooks; +}; diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..99f8cad --- /dev/null +++ b/main.cpp @@ -0,0 +1,81 @@ +/* + * File: main.cpp + * Author: hatkirby + * + * Created on August 10, 2013, 12:32 PM + */ + +#include +#include "IRC.h" +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * + */ + +char* hostname, nick, port, password, channel; + +char* _(const char* str) +{ + char* res = new char[strlen(str)+1]; + strcpy(res, str); + return res; +} + +int message(char* params, irc_reply_data* hostd, void* conn) +{ + std::string str(params); + std::string thetime(asctime(gettime())); + thetime = thetime.substr(4,15); + + if (*hostd->target != '#') + { + return 0; + } + + // Examine content of strings + + return 0; +} + +int end_of_motd(char* params, irc_reply_data* hostd, void* conn) +{ + IRC* irc_conn = (IRC*) conn; + irc_conn->privmsg(_("NickServ"), strcat(_("Identify "), password)); + irc_conn->join(channel); + irc_conn->hook_irc_command(_("PRIVMSG"), &message); + + return 0; +} + +void terminate(int param) +{ + exit(1); +} + +int main(int argc, char** argv) +{ + atexit(end_logging); + signal(SIGTERM, terminate); + + YAML::Node config = YAML::LoadFile("config.yml"); + hostname = _(config["hostname"].as().c_str()); + port = _(config["port"].as().c_str()); + nick = _(config["nick"].as().c_str()); + password = _(config["password"].as().c_str()); + channel = _(config["password"].as().c_str()); + + IRC conn; + conn.hook_irc_command("266", &end_of_motd); + conn.start(hostname, port, nick, nick, nick, password); + conn.message_loop(); + + return (EXIT_SUCCESS); +} -- cgit 1.4.1