]> jfr.im git - irc/quakenet/newserv.git/blob - chanserv/chanserv_grep.c
Move TS code around a bit.
[irc/quakenet/newserv.git] / chanserv / chanserv_grep.c
1
2 #include "chanserv.h"
3 #include "../core/events.h"
4 #include "../lib/irc_string.h"
5 #include <pcre.h>
6 #include <sys/poll.h>
7 #include <sys/types.h>
8 #include <sys/stat.h>
9 #include <fcntl.h>
10 #include <unistd.h>
11 #include <string.h>
12 #include <stdio.h>
13 #include <unistd.h>
14
15 #define CSG_BUFSIZE 1024
16 #define CSG_MAXSTARTPOINT 30
17
18 pcre *csg_curpat; /* Compiled pattern from pcre */
19 int csg_curfile; /* Which logfile is being searched */
20 unsigned long csg_curnum; /* What numeric is doing a search */
21 int csg_matches; /* How many lines have been returned so far */
22 int csg_maxmatches=0; /* How many matches are allowed */
23 int csg_direction; /* Log direction (0 = forward, 1 = reverse) */
24 int csg_bytesread;
25
26 char csg_readbuf[CSG_BUFSIZE]; /* Buffer */
27 int csg_bytesleft; /* How much valid data there is in the buffer */
28
29 void csg_handleevents(int fd, short revents);
30 int csg_dogrep(void *source, int cargc, char **cargv);
31 int csg_dorgrep(void *source, int cargc, char **cargv);
32 int csg_execgrep(nick *sender, char *pattern);
33
34 #if !defined(pread)
35 extern ssize_t pread(int fd, void *buf, size_t count, off_t offset);
36 #endif
37
38 void _init() {
39 chanservaddcommand("grep", QCMD_OPER, 1, csg_dogrep, "Searches the logs.","Usage: GREP <regex>\nSearches the logs. The current logfile will be specified first, followed by\nall older logfiles found. This will shuffle the order of results slightly. Where:\nregex - regular expression to search for.\nNote: For a case insensitive search, prepend (?i) to the regex.");
40 chanservaddcommand("rgrep", QCMD_OPER, 2, csg_dorgrep, "Searches the logs in reverse order.","Usage: RGREP <days> <regex>\nSearches the logs. The oldest specified log will be specified first meaning\nthat all events returned will be in strict chronological order. Where:\ndays - number of days of history to search\nregex - regex to search for\nNote: For a case insensitive search, prepend (?i) to the regex.");
41 }
42
43 void _fini() {
44 chanservremovecommand("grep", csg_dogrep);
45 chanservremovecommand("rgrep", csg_dorgrep);
46 }
47
48 int csg_dogrep(void *source, int cargc, char **cargv) {
49 nick *sender=source;
50
51 if (cargc<1) {
52 chanservstdmessage(sender, QM_NOTENOUGHPARAMS, "grep");
53 return CMD_ERROR;
54 }
55
56 csg_curfile=0;
57 csg_direction=0;
58 return csg_execgrep(sender, cargv[0]);
59 }
60
61 int csg_dorgrep(void *source, int cargc, char **cargv) {
62 int startpoint;
63 nick *sender=source;
64
65 if (cargc<2) {
66 chanservstdmessage(sender, QM_NOTENOUGHPARAMS, "rgrep");
67 return CMD_ERROR;
68 }
69
70 if (!protectedatoi(cargv[0], &startpoint)) {
71 chanservsendmessage(sender, "Error in starting day number.");
72 return CMD_ERROR;
73 }
74
75 if (startpoint<0) {
76 chanservsendmessage(sender, "Invalid starting day number.");
77 return CMD_ERROR;
78 }
79
80 if (startpoint>CSG_MAXSTARTPOINT) {
81 chanservsendmessage(sender, "Sorry, the maximum starting day is %d days.", CSG_MAXSTARTPOINT);
82 return CMD_ERROR;
83 }
84
85 csg_curfile=startpoint;
86 csg_direction=1;
87 return csg_execgrep(sender, cargv[1]);
88 }
89
90 int csg_execgrep(nick *sender, char *pattern) {
91 const char *errptr;
92 int erroffset;
93 int fd;
94 char filename[50];
95
96 if (csg_maxmatches>0) {
97 chanservsendmessage(sender, "Sorry, the grepper is currently busy - try later.");
98 return CMD_ERROR;
99 }
100
101 if (!(csg_curpat=pcre_compile(pattern, 0, &errptr, &erroffset, NULL))) {
102 chanservsendmessage(sender, "Error in pattern at character %d: %s",erroffset,errptr);
103 return CMD_ERROR;
104 }
105
106 if (csg_direction==0 || csg_curfile==0) {
107 if ((fd=open("chanservlog",O_RDONLY))<0) {
108 chanservsendmessage(sender, "Unable to open logfile.");
109 free(csg_curpat);
110 return CMD_ERROR;
111 }
112 } else {
113 sprintf(filename,"chanservlog.%d",csg_curfile);
114 if ((fd=open(filename,O_RDONLY))<0) {
115 chanservsendmessage(sender, "Unable to open logfile.");
116 free(csg_curpat);
117 return CMD_ERROR;
118 }
119 }
120
121 /* Initialise stuff for the match */
122 csg_maxmatches=500;
123 csg_matches=0;
124 csg_curnum=sender->numeric;
125 csg_bytesleft=0;
126 csg_bytesread=0;
127
128 registerhandler(fd, POLLIN, csg_handleevents);
129 chanservsendmessage(sender, "Started grep for %s...",pattern);
130
131 return CMD_OK;
132 }
133
134 void csg_handleevents(int fd, short revents) {
135 int res;
136 nick *np=getnickbynumeric(csg_curnum);
137 char *chp, *linestart;
138 char filename[50];
139 off_t pos;
140
141 /* If the target user has vanished, drop everything */
142 if (!np) {
143 deregisterhandler(fd, 1);
144 free(csg_curpat);
145 csg_maxmatches=0;
146 return;
147 }
148
149 retry:
150 res=read(fd, csg_readbuf+csg_bytesleft, CSG_BUFSIZE-csg_bytesleft);
151
152 if (res<=0) {
153 /* chanservsendmessage(np, "Closing file: res=%d, errno=%d(%s), bytes read=%d",res,errno,sys_errlist[errno],csg_bytesread); */
154 /* End of file (or error) */
155 deregisterhandler(fd, 1);
156 if (csg_direction==0) {
157 sprintf(filename,"chanservlog.%d",++csg_curfile);
158 } else {
159 csg_curfile--;
160 if (csg_curfile<0) {
161 chanservstdmessage(np, QM_ENDOFLIST);
162 free(csg_curpat);
163 csg_maxmatches=0;
164 return;
165 } else if (csg_curfile==0) {
166 sprintf(filename,"chanservlog");
167 } else {
168 sprintf(filename,"chanservlog.%d",csg_curfile);
169 }
170 }
171 if ((fd=open(filename,O_RDONLY))>=0) {
172 /* Found the next file */
173 registerhandler(fd, POLLIN, csg_handleevents);
174 } else {
175 chanservstdmessage(np, QM_ENDOFLIST);
176 free(csg_curpat);
177 csg_maxmatches=0;
178 }
179
180 return;
181 }
182
183 csg_bytesread+=res;
184
185 linestart=chp=csg_readbuf;
186 csg_bytesleft+=res;
187
188 while (csg_bytesleft) {
189 csg_bytesleft--;
190 if (*chp=='\r' || *chp=='\n' || *chp=='\0') {
191 if (linestart==chp) {
192 linestart=(++chp);
193 } else {
194 *chp++='\0';
195 if (!pcre_exec(csg_curpat, NULL, linestart, strlen(linestart), 0, 0, NULL, 0)) {
196 chanservsendmessage(np, "%s", linestart);
197 if (++csg_matches >= csg_maxmatches) {
198 chanservstdmessage(np, QM_ENDOFLIST);
199 free(csg_curpat);
200 deregisterhandler(fd, 1);
201 csg_maxmatches=0;
202 }
203 }
204 linestart=chp;
205 }
206 } else {
207 chp++;
208 }
209 }
210
211 csg_bytesleft=(chp-linestart);
212 memmove(csg_readbuf, linestart, csg_bytesleft);
213
214 /* BSD hack */
215 pos=lseek(fd, 0, SEEK_CUR);
216 if (!pread(fd, csg_readbuf+csg_bytesleft, 1, pos)) {
217 /* EOF */
218 goto retry;
219 }
220 }