├── .gitignore ├── Makefile ├── irc.c ├── irc.h ├── main.c ├── socket.c └── socket.h /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | ircbot 3 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | CC = gcc 3 | 4 | TARGET = ircbot 5 | 6 | OBJECTS = main.o irc.o socket.o 7 | 8 | all: $(TARGET) 9 | 10 | %.o: %.c 11 | $(CC) -g -c -o $@ $< 12 | 13 | clean: clean-obj clean-bin 14 | 15 | clean-obj: 16 | rm -rf *.o 17 | 18 | clean-bin: 19 | rm -rf $(TARGET) 20 | 21 | $(TARGET): $(OBJECTS) 22 | $(CC) -g -o $(TARGET) $(OBJECTS) 23 | -------------------------------------------------------------------------------- /irc.c: -------------------------------------------------------------------------------- 1 | #include "socket.h" 2 | #include "irc.h" 3 | #include 4 | #include 5 | 6 | int irc_connect(irc_t *irc, const char* server, const char* port) 7 | { 8 | if ( (irc->s = get_socket(server, port)) < 0 ) 9 | { 10 | return -1; 11 | } 12 | 13 | irc->bufptr = 0; 14 | 15 | return 0; 16 | } 17 | 18 | int irc_login(irc_t *irc, const char* nick) 19 | { 20 | return irc_reg(irc->s, nick, "arch", "HANSUDESU"); 21 | } 22 | 23 | int irc_join_channel(irc_t *irc, const char* channel) 24 | { 25 | strncpy(irc->channel, channel, 254); 26 | irc->channel[254] = '\0'; 27 | return irc_join(irc->s, channel); 28 | } 29 | 30 | int irc_leave_channel(irc_t *irc) 31 | { 32 | return irc_part(irc->s, irc->channel); 33 | } 34 | 35 | int irc_handle_data(irc_t *irc) 36 | { 37 | char tempbuffer[512]; 38 | int rc, i; 39 | 40 | if ( (rc = sck_recv(irc->s, tempbuffer, sizeof(tempbuffer) - 2 ) ) <= 0 ) 41 | { 42 | fprintf(stderr, ":v\n"); 43 | return -1; 44 | } 45 | 46 | tempbuffer[rc] = '\0'; 47 | 48 | for ( i = 0; i < rc; ++i ) 49 | { 50 | switch (tempbuffer[i]) 51 | { 52 | case '\r': 53 | case '\n': 54 | { 55 | irc->servbuf[irc->bufptr] = '\0'; 56 | irc->bufptr = 0; 57 | 58 | if ( irc_parse_action(irc) < 0 ) 59 | return -1; 60 | 61 | break; 62 | } 63 | 64 | default: 65 | { 66 | irc->servbuf[irc->bufptr] = tempbuffer[i]; 67 | if ( irc->bufptr >= (sizeof ( irc->servbuf ) -1 ) ) 68 | // Overflow! 69 | ; 70 | else 71 | irc->bufptr++; 72 | } 73 | } 74 | } 75 | return 0; 76 | } 77 | 78 | int irc_parse_action(irc_t *irc) 79 | { 80 | 81 | char irc_nick[128]; 82 | char irc_msg[512]; 83 | 84 | 85 | if ( strncmp(irc->servbuf, "PING :", 6) == 0 ) 86 | { 87 | return irc_pong(irc->s, &irc->servbuf[6]); 88 | } 89 | else if ( strncmp(irc->servbuf, "NOTICE AUTH :", 13) == 0 ) 90 | { 91 | // Don't care 92 | return 0; 93 | } 94 | else if ( strncmp(irc->servbuf, "ERROR :", 7) == 0 ) 95 | { 96 | // Still don't care 97 | return 0; 98 | } 99 | 100 | // Here be lvl. 42 dragonn boss 101 | // Parses IRC message that pulls out nick and message. 102 | else 103 | { 104 | char *ptr; 105 | int privmsg = 0; 106 | char irc_nick[128]; 107 | char irc_msg[512]; 108 | *irc_nick = '\0'; 109 | *irc_msg = '\0'; 110 | 111 | // Checks if we have non-message string 112 | if ( strchr(irc->servbuf, 1) != NULL ) 113 | return 0; 114 | 115 | if ( irc->servbuf[0] == ':' ) 116 | { 117 | ptr = strtok(irc->servbuf, "!"); 118 | if ( ptr == NULL ) 119 | { 120 | printf("ptr == NULL\n"); 121 | return 0; 122 | } 123 | else 124 | { 125 | strncpy(irc_nick, &ptr[1], 127); 126 | irc_nick[127] = '\0'; 127 | } 128 | 129 | while ( (ptr = strtok(NULL, " ")) != NULL ) 130 | { 131 | if ( strcmp(ptr, "PRIVMSG") == 0 ) 132 | { 133 | privmsg = 1; 134 | break; 135 | } 136 | } 137 | 138 | if ( privmsg ) 139 | { 140 | if ( (ptr = strtok(NULL, ":")) != NULL && (ptr = strtok(NULL, "")) != NULL ) 141 | { 142 | strncpy(irc_msg, ptr, 511); 143 | irc_msg[511] = '\0'; 144 | } 145 | } 146 | 147 | if ( privmsg == 1 && strlen(irc_nick) > 0 && strlen(irc_msg) > 0 ) 148 | { 149 | irc_log_message(irc, irc_nick, irc_msg); 150 | if ( irc_reply_message(irc, irc_nick, irc_msg) < 0 ) 151 | return -1; 152 | } 153 | } 154 | } 155 | return 0; 156 | } 157 | 158 | int irc_set_output(irc_t *irc, const char* file) 159 | { 160 | irc->file = fopen(file, "w"); 161 | if ( irc->file == NULL ) 162 | return -1; 163 | return 0; 164 | } 165 | 166 | int irc_reply_message(irc_t *irc, char *irc_nick, char *msg) 167 | { 168 | // Checks if someone calls on the bot. 169 | if ( *msg != '!' ) 170 | return 0; 171 | 172 | char *command; 173 | char *arg; 174 | // Gets command 175 | command = strtok(&msg[1], " "); 176 | arg = strtok(NULL, ""); 177 | if ( arg != NULL ) 178 | while ( *arg == ' ' ) 179 | arg++; 180 | 181 | if ( command == NULL ) 182 | return 0; 183 | 184 | if ( strcmp(command, "ping") == 0) 185 | { 186 | if ( irc_msg(irc->s, irc->channel, "pong") < 0) 187 | return -1; 188 | } 189 | else if ( strcmp(command, "war") == 0 ) 190 | { 191 | if ( irc_msg(irc->s, irc->channel, "WMs again? gtfo.") < 0 ) 192 | return -1; 193 | } 194 | else if ( strcmp(command, "smack") == 0 ) 195 | { 196 | char mesg[512]; 197 | srand(time(NULL)); 198 | int critical; 199 | critical = (rand()%10)/8; 200 | 201 | if ( arg != NULL && strlen(arg) > 0 ) 202 | { 203 | if ( critical ) 204 | snprintf(mesg, 511, "I smack thee, %s, for %d damage (it's super effective).", arg, rand()%20 + 21); 205 | else 206 | snprintf(mesg, 511, "I smack thee, %s, for %d damage.", arg, rand()%20 + 1); 207 | mesg[511] = '\0'; 208 | } 209 | else 210 | { 211 | snprintf(mesg, 511, "Behold, I smack thee, %s, for %d damage.", irc_nick, rand()%20 + 1); 212 | mesg[511] = '\0'; 213 | } 214 | if ( irc_msg(irc->s, irc->channel, mesg) < 0 ) 215 | return -1; 216 | } 217 | else if ( strcmp(command, "pacman") == 0 ) 218 | { 219 | if ( irc_msg(irc->s, irc->channel, "Wocka, wocka, bitches!") < 0 ) 220 | return -1; 221 | } 222 | else if ( strcmp(command, "google") == 0 ) 223 | { 224 | char mesg[512]; 225 | 226 | char t_nick[128]; 227 | char t_link[256]; 228 | char link[256] = {0}; 229 | 230 | char *t_arg = strtok(arg, " "); 231 | if ( t_arg ) 232 | { 233 | strncpy(t_nick, t_arg, 127); 234 | t_nick[127] = '\0'; 235 | } 236 | else 237 | return 0; 238 | 239 | t_arg = strtok(NULL, ""); 240 | if ( t_arg ) 241 | { 242 | while ( *t_arg == ' ' ) 243 | t_arg++; 244 | 245 | strncpy(t_link, t_arg, 255); 246 | t_link[255] = '\0'; 247 | } 248 | else 249 | return 0; 250 | 251 | t_arg = strtok(t_link, " "); 252 | while ( t_arg ) 253 | { 254 | strncpy(&link[strlen(link)], t_arg, 254 - strlen(link)); 255 | 256 | t_arg = strtok(NULL, " "); 257 | if ( !t_arg ) 258 | break; 259 | 260 | strncpy(&link[strlen(link)], "%20", 254 - strlen(link)); 261 | } 262 | 263 | 264 | 265 | snprintf(mesg, 511, "%s: http://lmgtfy.com/?q=%s", t_nick, link); 266 | mesg[511] = '\0'; 267 | if ( irc_msg(irc->s, irc->channel, mesg) < 0 ) 268 | return -1; 269 | } 270 | 271 | return 0; 272 | } 273 | 274 | int irc_log_message(irc_t *irc, const char* nick, const char* message) 275 | { 276 | char timestring[128]; 277 | time_t curtime; 278 | time(&curtime); 279 | strftime(timestring, 127, "%F - %H:%M:%S", localtime(&curtime)); 280 | timestring[127] = '\0'; 281 | 282 | fprintf(irc->file, "%s - [%s] <%s> %s\n", irc->channel, timestring, nick, message); 283 | fflush(irc->file); 284 | } 285 | 286 | void irc_close(irc_t *irc) 287 | { 288 | close(irc->s); 289 | fclose(irc->file); 290 | } 291 | 292 | 293 | // irc_pong: For answering pong requests... 294 | int irc_pong(int s, const char *data) 295 | { 296 | return sck_sendf(s, "PONG :%s\r\n", data); 297 | } 298 | 299 | // irc_reg: For registering upon login 300 | int irc_reg(int s, const char *nick, const char *username, const char *fullname) 301 | { 302 | return sck_sendf(s, "NICK %s\r\nUSER %s localhost 0 :%s\r\n", nick, username, fullname); 303 | } 304 | 305 | // irc_join: For joining a channel 306 | int irc_join(int s, const char *data) 307 | { 308 | return sck_sendf(s, "JOIN %s\r\n", data); 309 | 310 | } 311 | 312 | // irc_part: For leaving a channel 313 | int irc_part(int s, const char *data) 314 | { 315 | return sck_sendf(s, "PART %s\r\n", data); 316 | 317 | } 318 | 319 | // irc_nick: For changing your nick 320 | int irc_nick(int s, const char *data) 321 | { 322 | return sck_sendf(s, "NICK %s\r\n", data); 323 | 324 | } 325 | 326 | // irc_quit: For quitting IRC 327 | int irc_quit(int s, const char *data) 328 | { 329 | return sck_sendf(s, "QUIT :%s\r\n", data); 330 | } 331 | 332 | // irc_topic: For setting or removing a topic 333 | int irc_topic(int s, const char *channel, const char *data) 334 | { 335 | return sck_sendf(s, "TOPIC %s :%s\r\n", channel, data); 336 | } 337 | 338 | // irc_action: For executing an action (.e.g /me is hungry) 339 | int irc_action(int s, const char *channel, const char *data) 340 | { 341 | return sck_sendf(s, "PRIVMSG %s :\001ACTION %s\001\r\n", channel, data); 342 | } 343 | 344 | // irc_msg: For sending a channel message or a query 345 | int irc_msg(int s, const char *channel, const char *data) 346 | { 347 | return sck_sendf(s, "PRIVMSG %s :%s\r\n", channel, data); 348 | } 349 | 350 | -------------------------------------------------------------------------------- /irc.h: -------------------------------------------------------------------------------- 1 | #ifndef __IRC_H 2 | #define __IRC_H 3 | 4 | #include 5 | 6 | typedef struct 7 | { 8 | int s; 9 | FILE *file; 10 | char channel[256]; 11 | char *nick; 12 | char servbuf[512]; 13 | int bufptr; 14 | } irc_t; 15 | 16 | int irc_connect(irc_t *irc, const char* server, const char* port); 17 | int irc_login(irc_t *irc, const char* nick); 18 | int irc_join_channel(irc_t *irc, const char* channel); 19 | int irc_leave_channel(irc_t *irc); 20 | int irc_handle_data(irc_t *irc); 21 | int irc_set_output(irc_t *irc, const char* file); 22 | int irc_parse_action(irc_t *irc); 23 | int irc_log_message(irc_t *irc, const char *nick, const char* msg); 24 | int irc_reply_message(irc_t *irc, char *nick, char* msg); 25 | void irc_close(irc_t *irc); 26 | 27 | // IRC Protocol 28 | int irc_pong(int s, const char *pong); 29 | int irc_reg(int s, const char *nick, const char *username, const char *fullname); 30 | int irc_join(int s, const char *channel); 31 | int irc_part(int s, const char *data); 32 | int irc_nick(int s, const char *nick); 33 | int irc_quit(int s, const char *quit_msg); 34 | int irc_topic(int s, const char *channel, const char *data); 35 | int irc_action(int s, const char *channel, const char *data); 36 | int irc_msg(int s, const char *channel, const char *data); 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | #include "socket.h" 2 | #include "irc.h" 3 | 4 | int main(int argc, char **argv) 5 | { 6 | irc_t irc; 7 | 8 | if ( irc_connect(&irc, "irc.freenode.org", "6667") < 0 ) 9 | { 10 | fprintf(stderr, "Connection failed.\n"); 11 | goto exit_err; 12 | } 13 | 14 | irc_set_output(&irc, "/dev/stdout"); 15 | 16 | if ( irc_login(&irc, "maister_") < 0 ) 17 | { 18 | fprintf(stderr, "Couldn't log in.\n"); 19 | goto exit_err; 20 | } 21 | 22 | if ( irc_join_channel(&irc, "#umgz") < 0 ) 23 | { 24 | fprintf(stderr, "Couldn't join channel.\n"); 25 | goto exit_err; 26 | } 27 | 28 | while ( irc_handle_data(&irc) >= 0 ); 29 | 30 | irc_close(&irc); 31 | return 0; 32 | 33 | exit_err: 34 | irc_close(&irc); 35 | exit(1); 36 | } 37 | 38 | -------------------------------------------------------------------------------- /socket.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | int get_socket(const char* host, const char* port) 12 | { 13 | int rc; 14 | int s; 15 | struct addrinfo hints, *res; 16 | 17 | memset(&hints, 0, sizeof(hints)); 18 | 19 | hints.ai_family = AF_UNSPEC; 20 | hints.ai_socktype = SOCK_STREAM; 21 | hints.ai_flags = AI_PASSIVE; 22 | 23 | if ((rc = getaddrinfo(host, port, &hints, &res) ) < 0 ) 24 | { 25 | fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(rc)); 26 | return -1; 27 | } 28 | 29 | s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); 30 | if ( s < 0 ) 31 | { 32 | fprintf(stderr, "Couldn't get socket.\n"); 33 | goto error; 34 | } 35 | 36 | if ( connect(s, res->ai_addr, res->ai_addrlen) < 0 ) 37 | { 38 | fprintf(stderr, "Couldn't connect.\n"); 39 | goto error; 40 | } 41 | 42 | freeaddrinfo(res); 43 | return s; 44 | 45 | error: 46 | freeaddrinfo(res); 47 | return -1; 48 | 49 | } 50 | 51 | int sck_send(int s, const char* data, size_t size) 52 | { 53 | size_t written = 0; 54 | int rc; 55 | 56 | while ( written < size ) 57 | { 58 | rc = send(s, data + written, size - written, 0); 59 | if ( rc <= 0 ) 60 | return -1; 61 | 62 | written += rc; 63 | } 64 | 65 | return written; 66 | } 67 | 68 | int sck_sendf(int s, const char *fmt, ...) 69 | { 70 | char send_buf[512]; 71 | int send_len; 72 | va_list args; 73 | 74 | if (strlen(fmt) != 0 ) 75 | { 76 | // Format the data 77 | va_start(args, fmt); 78 | send_len = vsnprintf(send_buf, sizeof (send_buf), fmt, args); 79 | va_end(args); 80 | 81 | // Clamp the chunk 82 | if (send_len > 512) 83 | send_len = 512; 84 | 85 | if (sck_send( s, send_buf, send_len ) <= 0) 86 | return -1; 87 | return send_len; 88 | } 89 | return 0; 90 | } 91 | 92 | int sck_recv(int s, char* buffer, size_t size) 93 | { 94 | int rc; 95 | 96 | rc = recv(s, buffer, size, 0); 97 | if ( rc <= 0 ) 98 | return -1; 99 | 100 | return rc; 101 | } 102 | 103 | -------------------------------------------------------------------------------- /socket.h: -------------------------------------------------------------------------------- 1 | #ifndef IRC_SOCKET_H 2 | #define IRC_SOCKET_H 3 | 4 | #include 5 | 6 | int get_socket(const char* host, const char* port); 7 | int sck_send(int socket, const char* data, size_t size); 8 | int sck_sendf(int socket, const char* fmt, ...); 9 | int sck_recv(int socket, char* buffer, size_t size); 10 | 11 | #endif 12 | --------------------------------------------------------------------------------