1 /**
2 * Copyright (C) 2016 Aaron Ball <nullspoon@oper.io>
3 *
4 * Ircbot is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * Ircbot is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with ircbot. If not, see <http://www.gnu.org/licenses/>.
16 */
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <unistd.h>
20 #include <string.h>
21 #include <errno.h>
22 #include <unistd.h>
23
24 /* Networking libs */
25 #include <arpa/inet.h>
26 #include <sys/types.h>
27 #include <sys/socket.h>
28 #include <netdb.h>
29
30
31 // For trapping Ctrl+c
32 #include <signal.h>
33
34 #include "common.h"
35
36 #define buflen 512
37
38 static int socket_desc;
39
40 int newconn(char* addr, char* port) {
41 int status;
42 int socket_desc;
43 struct addrinfo hints, *p;
44 struct addrinfo *servinfo;
45
46 // Ensure our struct is empty
47 memset(&hints, 0, sizeof(hints));
48
49 // Set hints struct
50 hints.ai_flags = AI_PASSIVE;
51 hints.ai_family = AF_UNSPEC;
52 hints.ai_socktype = SOCK_STREAM;
53
54 if((status = getaddrinfo(addr, port, &hints, &servinfo)) != 0) {
55 fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(status));
56 exit(1);
57 }
58
59 // Iterrate the dns entries
60 for(p = servinfo;p != NULL; p = p->ai_next) {
61 // Attempt to create socket
62 socket_desc = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
63
64 // If socket creation failed, skip entry
65 if (socket_desc == -1) continue;
66
67 // Attempt to connect. If successful, break out of loop
68 if (connect(socket_desc, p->ai_addr, p->ai_addrlen) != -1) break;
69 }
70
71 return socket_desc;
72 }
73
74
75 int recv_line(int sockd, char* out) {
76 int i = 0;
77 char c = '\0';
78
79 while(c != '\n') {
80 recv(sockd, &c, 1, 0);
81 out[i] = c;
82 i++;
83 }
84 out[i] = '\0';
85 return i;
86 }
87
88
89 char* irc_get_msg(char* str, char* buf ) {
90 int i = 2;
91 int bufi = 0;
92 // Place the start cursor
93 while(i < strlen(str)) {
94 if(str[i] == ':') {
95 i++;
96 printf("Found beginning of message at index %d\n", i);
97 break;
98 }
99 i++;
100 }
101
102 while(str[i] != '\r' && str[i] != '\n' && str[i] != '\0') {
103 buf[bufi] = str[i];
104 bufi++;
105 i++;
106 }
107
108 buf[bufi] = '\0';
109 return buf;
110 }
111
112
113 int doloop(int sockd, int ret, char* chan) {
114 char buf[buflen];
115 char resp[buflen];
116 char msg[1024];
117 int len;
118
119 while(1) {
120 len = recv_line(sockd, buf);
121 if(len == 0) continue;
122
123 if(strncmp(buf, "PING", 4) == 0) {
124 sprintf(&resp[0], "PONG %s", &buf[5]);
125 printf("pong: %s", resp);
126 send(sockd, resp, strlen(resp), 0);
127 if(ret == 1) return 0;
128 } else if(strstr(buf, "ircbot quit") != NULL) {
129 // Quit command
130 break;
131 } else if(strstr(buf, "ircbot say ") != NULL) {
132 // The say command
133 irc_get_msg(buf, msg);
134 sprintf(&resp[0], "PRIVMSG %s :%s\n", chan, &msg[11]);
135 printf("Say command received. Saying \"%s\"\n", &msg[11]);
136 send(sockd, resp, strlen(resp), 0);
137 } else if(strstr(buf, "ircbot meaning of life") != NULL) {
138 // The mol command
139 sprintf(&resp[0], "PRIVMSG %s :%d\n", chan, 42);
140 send(sockd, resp, strlen(resp), 0);
141 } else if(strstr(buf, "Looking up your hostname") != NULL) {
142 // Receive next line
143 recv_line(sockd, buf);
144 printf(buf);
145 break;
146 } else if(strstr(buf, "Nickname is already in use.") != NULL) {
147 // We can't proceed if nickname is already in use.
148 printf(buf);
149 return -1;
150 }
151
152 printf(buf);
153 //len = 0;
154 }
155
156 return 0;
157 }
158
159
160 int irc_auth(int sockd, char* nick, char* user, char* chan) {
161 int status;
162 char nickstr[buflen];
163 char userstr[buflen];
164 char joinstr[buflen];
165
166 // Compose NICK statement
167 sprintf(nickstr, "NICK %s\n", nick);
168 // Compose NICK statement
169 sprintf(userstr, "USER %s 0 * : %s\n", nick, user);
170 // Compose the JOIN statement
171 sprintf(joinstr, "JOIN %s\n", chan);
172
173 // Wait for hostname identification
174 doloop(sockd, 1, chan);
175
176 // Send NICK command
177 send(sockd, nickstr, strlen(nickstr), 0);
178 printf("%s\n", nickstr);
179
180 // Send USER command
181 send(sockd, userstr, strlen(userstr), 0);
182 printf("%s\n", userstr);
183
184 // Wait for ping and send pong response
185 printf("Waiting for initial ping\n");
186 status = doloop(sockd, 1, chan);
187 if(status == -1) return -1;
188
189 // Send JOIN command
190 printf("Joining channel %s\n", chan);
191 send(sockd, joinstr, strlen(joinstr), 0);
192
193 printf("Entering main watcher loop\n");
194 doloop(sockd, 0, chan);
195
196 // send quit message
197 char quitstr[512];
198 sprintf(quitstr, "QUIT :Blowing this popsicle stand\n");
199 send(sockd, quitstr, strlen(quitstr), 0);
200 close(sockd);
201
202 return 0;
203 }
204
205 void quit(int signal) {
206 char quitstr[512];
207 sprintf(quitstr, "QUIT :Force quit!\n");
208 send(socket_desc, quitstr, strlen(quitstr), 0);
209 printf("\n\nQuitting, signal %d\n\n\n", signal);
210
211 //doloop(socket_desc, 1);
212 close(socket_desc);
213 exit(128 + signal);
214 }
215
216
217 int main(int argc, char* argv[]) {
218 char *server = argv[1];
219 char *port = argv[2];
220 char *nick = argv[3];
221 char *chan = argv[4];
222 int status;
223
224 if(argc < 4) {
225 printf("\nERROR: Irc server, port, and nick required to connect\n\n");
226 printf("Usage:\n ircbot irc.server.tld 6667 jcricket\n\n");
227 return 1;
228 }
229
230 //int socket_desc;
231
232 socket_desc = newconn(server, port);
233
234 if(socket_desc == -1) {
235 printf("Connection error\n");
236 return 1;
237 }
238
239 signal(SIGINT, quit);
240
241
242 status = irc_auth(socket_desc, nick, nick, chan);
243 if(status == -1) return 1;
244
245 // Cleanup
246 close(socket_desc);
247
248 return 0;
249 }
|