Subversion Repositories Okuu

Rev

Rev 8 | Rev 12 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 8 Rev 11
Line 1... Line 1...
1
/* $Id: bot.c 8 2024-09-11 00:41:52Z nishi $ */
1
/* $Id: bot.c 11 2024-09-11 10:24:20Z nishi $ */
2
 
2
 
3
#include "ok_bot.h"
3
#include "ok_bot.h"
4
 
4
 
5
#include "ok_util.h"
5
#include "ok_util.h"
6
#include "ok_news.h"
6
#include "ok_news.h"
Line 40... Line 40...
40
extern int ircport;
40
extern int ircport;
41
 
41
 
42
int ok_sock;
42
int ok_sock;
43
struct sockaddr_in ok_addr;
43
struct sockaddr_in ok_addr;
44
 
44
 
45
void ok_close(int sock){
45
void ok_close(int sock) { close(sock); }
46
	close(sock);
-
 
47
}
-
 
48
 
46
 
49
void ok_bot_kill(int sig){
47
void ok_bot_kill(int sig) {
50
	fprintf(stderr, "Shutdown\n");
48
	fprintf(stderr, "Shutdown\n");
51
	ircfw_socket_send_cmd(ok_sock, NULL, "QUIT :Shutdown (Signal)");
49
	ircfw_socket_send_cmd(ok_sock, NULL, "QUIT :Shutdown (Signal)");
52
	exit(1);
50
	exit(1);
53
}
51
}
54
 
52
 
Line 58... Line 56...
58
		if(!('0' <= str[i] && str[i] <= '9')) return false;
56
		if(!('0' <= str[i] && str[i] <= '9')) return false;
59
	}
57
	}
60
	return true;
58
	return true;
61
}
59
}
62
 
60
 
63
char* ok_null(const char* str){
-
 
64
	return str == NULL ? "(null)" : (char*)str;
61
char* ok_null(const char* str) { return str == NULL ? "(null)" : (char*)str; }
65
}
-
 
66
 
62
 
67
int namesort(const struct dirent** a_, const struct dirent** b_){
63
int namesort(const struct dirent** a_, const struct dirent** b_) {
68
	const struct dirent* a = *a_;
64
	const struct dirent* a = *a_;
69
	const struct dirent* b = *b_;
65
	const struct dirent* b = *b_;
70
	return atoi(a->d_name) - atoi(b->d_name);
66
	return atoi(a->d_name) - atoi(b->d_name);
71
}
67
}
72
 
68
 
73
int nodots(const struct dirent* d){
-
 
74
	return (strcmp(d->d_name, "..") == 0 || strcmp(d->d_name, ".") == 0) ? 0 : 1;
69
int nodots(const struct dirent* d) { return (strcmp(d->d_name, "..") == 0 || strcmp(d->d_name, ".") == 0) ? 0 : 1; }
75
}
-
 
76
 
70
 
77
void ok_bot(void){
71
void ok_bot(void) {
78
	if((ok_sock = socket(PF_INET, SOCK_STREAM, 0)) < 0){
72
	if((ok_sock = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
79
		fprintf(stderr, "Socket creation failure\n");
73
		fprintf(stderr, "Socket creation failure\n");
80
		return;
74
		return;
81
	}
75
	}
82
 
76
 
83
	bzero((char*)&ok_addr, sizeof(ok_addr));
77
	bzero((char*)&ok_addr, sizeof(ok_addr));
Line 90... Line 84...
90
	if(setsockopt(ok_sock, IPPROTO_TCP, TCP_NODELAY, (char*)&yes, sizeof(yes)) < 0) {
84
	if(setsockopt(ok_sock, IPPROTO_TCP, TCP_NODELAY, (char*)&yes, sizeof(yes)) < 0) {
91
		fprintf(stderr, "setsockopt failure");
85
		fprintf(stderr, "setsockopt failure");
92
		ok_close(ok_sock);
86
		ok_close(ok_sock);
93
		return;
87
		return;
94
	}
88
	}
95
	
89
 
96
	if(connect(ok_sock, (struct sockaddr*)&ok_addr, sizeof(ok_addr)) < 0){
90
	if(connect(ok_sock, (struct sockaddr*)&ok_addr, sizeof(ok_addr)) < 0) {
97
		fprintf(stderr, "Connection failure\n");
91
		fprintf(stderr, "Connection failure\n");
98
		ok_close(ok_sock);
92
		ok_close(ok_sock);
99
		return;
93
		return;
100
	}
94
	}
101
 
95
 
102
	signal(SIGINT, ok_bot_kill);
96
	signal(SIGINT, ok_bot_kill);
103
	signal(SIGTERM, ok_bot_kill);
97
	signal(SIGTERM, ok_bot_kill);
104
 
98
 
105
	char* construct = malloc(1025);
99
	char* construct = malloc(1025);
106
 
100
 
107
	if(ircpass != NULL && strlen(ircpass) > 0){
101
	if(ircpass != NULL && strlen(ircpass) > 0) {
108
		sprintf(construct, "PASS :%s", ircpass);
102
		sprintf(construct, "PASS :%s", ircpass);
109
		ircfw_socket_send_cmd(ok_sock, NULL, construct);
103
		ircfw_socket_send_cmd(ok_sock, NULL, construct);
110
	}
104
	}
111
 
105
 
112
	sprintf(construct, "USER %s %s %s :%s", ircuser, ircuser, ircuser, ircreal);
106
	sprintf(construct, "USER %s %s %s :%s", ircuser, ircuser, ircuser, ircreal);
Line 120... Line 114...
120
 
114
 
121
	struct pollfd pollfds[1];
115
	struct pollfd pollfds[1];
122
	pollfds[0].fd = ok_sock;
116
	pollfds[0].fd = ok_sock;
123
	pollfds[0].events = POLLIN | POLLPRI;
117
	pollfds[0].events = POLLIN | POLLPRI;
124
 
118
 
125
	while(1){
119
	while(1) {
126
		int r = poll(pollfds, 1, 100);
120
		int r = poll(pollfds, 1, 100);
127
		if(!(r > 0 && pollfds[0].revents & POLLIN)){
121
		if(!(r > 0 && pollfds[0].revents & POLLIN)) {
128
			/* 100ms sleep, technically */
122
			/* 100ms sleep, technically */
129
			uint64_t count = 0;
123
			uint64_t count = 0;
130
			FILE* f = fopen(nntpcount, "rb");
124
			FILE* f = fopen(nntpcount, "rb");
131
			if(f != NULL){
125
			if(f != NULL) {
132
				fread(&count, sizeof(count), 1, f);
126
				fread(&count, sizeof(count), 1, f);
133
				fclose(f);
127
				fclose(f);
134
			}
128
			}
135
			struct dirent** list;
129
			struct dirent** list;
136
			int n = scandir(nntppath, &list, nodots, namesort);
130
			int n = scandir(nntppath, &list, nodots, namesort);
137
			if(n >= 0){
131
			if(n >= 0) {
138
				int i;
132
				int i;
139
				for(i = 0; i < n; i++){
133
				for(i = 0; i < n; i++) {
140
					if(!sendable){
134
					if(!sendable) {
141
						free(list[i]);
135
						free(list[i]);
142
						continue;
136
						continue;
143
					}
137
					}
144
					if(count <= atoi(list[i]->d_name)){
138
					if(count <= atoi(list[i]->d_name)) {
145
						sprintf(construct, "%s/%s", nntppath, list[i]->d_name);
139
						sprintf(construct, "%s/%s", nntppath, list[i]->d_name);
146
						if(ok_news_read(construct) == 0){
140
						if(ok_news_read(construct) == 0) {
147
							if(strcmp(news_entry.from, nntpfrom) != 0){
141
							if(strcmp(news_entry.from, nntpfrom) != 0) {
148
								char* tmp = ok_strcat3("PRIVMSG ", ircchan, " :\x03" "07[USENET] ~ ");
142
								char* tmp = ok_strcat3("PRIVMSG ", ircchan,
-
 
143
										       " :\x03"
-
 
144
										       "07[USENET] ~ ");
149
								char* temp = ok_strcat3(tmp, news_entry.from, "\x03 ");
145
								char* temp = ok_strcat3(tmp, news_entry.from, "\x03 ");
150
								free(tmp);
146
								free(tmp);
151
								int j;
147
								int j;
152
								int incr = 0;
148
								int incr = 0;
153
								for(j = 0;; j++){
149
								for(j = 0;; j++) {
154
									if(news_entry.content[j] == 0 || news_entry.content[j] == '\n'){
150
									if(news_entry.content[j] == 0 || news_entry.content[j] == '\n') {
155
										char* line = malloc(j - incr + 1);
151
										char* line = malloc(j - incr + 1);
156
										line[j - incr] = 0;
152
										line[j - incr] = 0;
157
										memcpy(line, news_entry.content + incr, j - incr);
153
										memcpy(line, news_entry.content + incr, j - incr);
158
	
154
 
159
										if(strlen(line) > 0){
155
										if(strlen(line) > 0) {
160
											char* msg = ok_strcat(temp, line);
156
											char* msg = ok_strcat(temp, line);
161
											ircfw_socket_send_cmd(ok_sock, NULL, msg);
157
											ircfw_socket_send_cmd(ok_sock, NULL, msg);
162
											free(msg);
158
											free(msg);
163
											usleep(1000 * 100); /* Sleep for 100ms */
159
											usleep(1000 * 100); /* Sleep for 100ms */
164
										}
160
										}
165
	
161
 
166
										free(line);
162
										free(line);
167
										incr = j + 1;
163
										incr = j + 1;
168
										if(news_entry.content[j] == 0) break;
164
										if(news_entry.content[j] == 0) break;
169
									}
165
									}
170
								}
166
								}
171
								free(temp);
167
								free(temp);
172
							}
168
							}
173
						}else{
169
						} else {
174
							fprintf(stderr, "Could not read %s\n", construct);
170
							fprintf(stderr, "Could not read %s\n", construct);
175
						}
171
						}
176
					}
172
					}
177
					free(list[i]);
173
					free(list[i]);
178
				}
174
				}
179
				count = atoi(list[i - 1]->d_name) + 1;
175
				count = atoi(list[i - 1]->d_name) + 1;
180
				free(list);
176
				free(list);
181
			}
177
			}
182
			if(sendable){
178
			if(sendable) {
183
				f = fopen(nntpcount, "wb");
179
				f = fopen(nntpcount, "wb");
184
				if(f != NULL){
180
				if(f != NULL) {
185
					fwrite(&count, sizeof(count), 1, f);
181
					fwrite(&count, sizeof(count), 1, f);
186
					fclose(f);
182
					fclose(f);
187
				}
183
				}
188
			}
184
			}
189
			continue;
185
			continue;
190
		}
186
		}
191
		int st = ircfw_socket_read_cmd(ok_sock);
187
		int st = ircfw_socket_read_cmd(ok_sock);
192
		if(st != 0){
188
		if(st != 0) {
193
			fprintf(stderr, "Bad response\n");
189
			fprintf(stderr, "Bad response\n");
194
			return;
190
			return;
195
		}
191
		}
196
		if(strlen(ircfw_message.command) == 3 && ok_is_number(ircfw_message.command)){
192
		if(strlen(ircfw_message.command) == 3 && ok_is_number(ircfw_message.command)) {
197
			int res = atoi(ircfw_message.command);
193
			int res = atoi(ircfw_message.command);
198
			if(!is_in && 400 <= res && res <= 599){
194
			if(!is_in && 400 <= res && res <= 599) {
199
				fprintf(stderr, "Bad response\n");
195
				fprintf(stderr, "Bad response\n");
200
				return;
196
				return;
201
			}else if(400 <= res && res <= 599){
197
			} else if(400 <= res && res <= 599) {
202
				fprintf(stderr, "Ignored error: %d\n", res);
198
				fprintf(stderr, "Ignored error: %d\n", res);
203
				continue;
199
				continue;
204
			}
200
			}
205
			if(res == 376){
201
			if(res == 376) {
206
				is_in = true;
202
				is_in = true;
207
				fprintf(stderr, "Login successful\n");
203
				fprintf(stderr, "Login successful\n");
208
				sprintf(construct, "JOIN :%s", ircchan);
204
				sprintf(construct, "JOIN :%s", ircchan);
209
				ircfw_socket_send_cmd(ok_sock, NULL, construct);
205
				ircfw_socket_send_cmd(ok_sock, NULL, construct);
210
			}else if(res == 331 || res == 332){
206
			} else if(res == 331 || res == 332) {
211
				sendable = true;
207
				sendable = true;
212
			}
208
			}
213
		}else{
209
		} else {
214
			if(strcasecmp(ircfw_message.command, "PING") == 0){
210
			if(strcasecmp(ircfw_message.command, "PING") == 0) {
215
				fprintf(stderr, "Ping request\n");
211
				fprintf(stderr, "Ping request\n");
216
				sprintf(construct, "PONG :%s", ok_null(ircfw_message.prefix));
212
				sprintf(construct, "PONG :%s", ok_null(ircfw_message.prefix));
217
				ircfw_socket_send_cmd(ok_sock, NULL, construct);
213
				ircfw_socket_send_cmd(ok_sock, NULL, construct);
218
			}else if(strcasecmp(ircfw_message.command, "PRIVMSG") == 0){
214
			} else if(strcasecmp(ircfw_message.command, "PRIVMSG") == 0) {
219
				char* prefix = ircfw_message.prefix;
215
				char* prefix = ircfw_message.prefix;
220
				char** params = ircfw_message.params;
216
				char** params = ircfw_message.params;
221
 
217
 
222
				int len = 0;
218
				int len = 0;
223
				if(params != NULL) {
219
				if(params != NULL) {
224
					int i;
220
					int i;
225
					for(i = 0; params[i] != NULL; i++);
221
					for(i = 0; params[i] != NULL; i++)
-
 
222
						;
226
					len = i;
223
					len = i;
227
				}
224
				}
228
				if(prefix != NULL && len == 2) {
225
				if(prefix != NULL && len == 2) {
229
					char* sentin = params[0];
226
					char* sentin = params[0];
230
					char* msg = params[1];
227
					char* msg = params[1];
Line 234... Line 231...
234
						if(nick[i] == '!') {
231
						if(nick[i] == '!') {
235
							nick[i] = 0;
232
							nick[i] = 0;
236
							break;
233
							break;
237
						}
234
						}
238
					}
235
					}
239
					if(msg[0] == 1 && msg[strlen(msg) - 1] == 1){
236
					if(msg[0] == 1 && msg[strlen(msg) - 1] == 1) {
240
						/* CTCP */
237
						/* CTCP */
241
						if(strcasecmp(msg, "\x01VERSION\x01") == 0){
238
						if(strcasecmp(msg, "\x01VERSION\x01") == 0) {
242
							sprintf(construct, "NOTICE %s :\x01VERSION Okuu %s / IRC Frameworks %s: http://nishi.boats/okuu\x01", nick, OKUU_VERSION, IRCFW_VERSION);
239
							sprintf(construct, "NOTICE %s :\x01VERSION Okuu %s / IRC Frameworks %s: http://nishi.boats/okuu\x01", nick, OKUU_VERSION, IRCFW_VERSION);
243
							ircfw_socket_send_cmd(ok_sock, NULL, construct);
240
							ircfw_socket_send_cmd(ok_sock, NULL, construct);
244
						}
241
						}
245
					}else if(sentin[0] == '#'){
242
					} else if(sentin[0] == '#') {
246
						/* This was sent in channel */
243
						/* This was sent in channel */
247
						if(ok_news_write(nick, msg) != 0){
244
						if(ok_news_write(nick, msg) != 0) {
248
							sprintf(construct, "PRIVMSG %s :Could not send the message to the USENET", sentin);
245
							sprintf(construct, "PRIVMSG %s :Could not send the message to the USENET", sentin);
249
							ircfw_socket_send_cmd(ok_sock, NULL, construct);
246
							ircfw_socket_send_cmd(ok_sock, NULL, construct);
250
						}
247
						}
251
					}
248
					}
252
 
249
 
253
					free(nick);
250
					free(nick);
254
				}
251
				}
255
			}else if(strcasecmp(ircfw_message.command, "ERROR") == 0){
252
			} else if(strcasecmp(ircfw_message.command, "ERROR") == 0) {
256
				if(ircfw_message.params != NULL){
253
				if(ircfw_message.params != NULL) {
257
					int i;
254
					int i;
258
					for(i = 0; ircfw_message.params[i] != NULL; i++) fprintf(stderr, "ERROR: %s\n", ircfw_message.params[i]);
255
					for(i = 0; ircfw_message.params[i] != NULL; i++) fprintf(stderr, "ERROR: %s\n", ircfw_message.params[i]);
259
				}
256
				}
260
			}
257
			}
261
		}
258
		}