]> jfr.im git - irc/quakenet/newserv.git/blame - chanserv/chanserv_grep.c
A4STATS: remove E style escapes and switch to createtable for indices
[irc/quakenet/newserv.git] / chanserv / chanserv_grep.c
CommitLineData
c86edd1d
Q
1
2#include "chanserv.h"
3#include "../core/events.h"
107ccb4c 4#include "../lib/irc_string.h"
c86edd1d
Q
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>
4ad1cf7a 13#include <unistd.h>
7f32dbdf
P
14#include "../lib/version.h"
15
16MODULE_VERSION(QVERSION)
c86edd1d 17
43583524 18#define CSG_BUFSIZE 1024
71c362ef 19#define CSG_MAXSTARTPOINT 30
c86edd1d
Q
20
21pcre *csg_curpat; /* Compiled pattern from pcre */
22int csg_curfile; /* Which logfile is being searched */
23unsigned long csg_curnum; /* What numeric is doing a search */
24int csg_matches; /* How many lines have been returned so far */
25int csg_maxmatches=0; /* How many matches are allowed */
107ccb4c 26int csg_direction; /* Log direction (0 = forward, 1 = reverse) */
43583524 27int csg_bytesread;
c86edd1d
Q
28
29char csg_readbuf[CSG_BUFSIZE]; /* Buffer */
30int csg_bytesleft; /* How much valid data there is in the buffer */
31
32void csg_handleevents(int fd, short revents);
33int csg_dogrep(void *source, int cargc, char **cargv);
107ccb4c
C
34int csg_dorgrep(void *source, int cargc, char **cargv);
35int csg_execgrep(nick *sender, char *pattern);
c86edd1d 36
4ad1cf7a
CP
37#if !defined(pread)
38extern ssize_t pread(int fd, void *buf, size_t count, off_t offset);
39#endif
40
c86edd1d 41void _init() {
71c362ef 42 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.");
9b9d3d58 43 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.");
c86edd1d
Q
44}
45
46void _fini() {
47 chanservremovecommand("grep", csg_dogrep);
107ccb4c 48 chanservremovecommand("rgrep", csg_dorgrep);
c86edd1d
Q
49}
50
51int csg_dogrep(void *source, int cargc, char **cargv) {
52 nick *sender=source;
710793ad
CP
53 reguser *rup=getreguserfromnick(sender);
54
55 if (!rup)
56 return CMD_ERROR;
c86edd1d
Q
57
58 if (cargc<1) {
59 chanservstdmessage(sender, QM_NOTENOUGHPARAMS, "grep");
60 return CMD_ERROR;
61 }
62
107ccb4c
C
63 csg_curfile=0;
64 csg_direction=0;
710793ad
CP
65
66 chanservwallmessage("%s (%s) used GREP %s", sender->nick, rup->username, cargv[0]);
67 cs_log(sender, "GREP %s", cargv[0]);
68
107ccb4c
C
69 return csg_execgrep(sender, cargv[0]);
70}
71
72int csg_dorgrep(void *source, int cargc, char **cargv) {
73 int startpoint;
74 nick *sender=source;
710793ad
CP
75 reguser *rup=getreguserfromnick(sender);
76
77 if (!rup)
78 return CMD_ERROR;
107ccb4c
C
79
80 if (cargc<2) {
81 chanservstdmessage(sender, QM_NOTENOUGHPARAMS, "rgrep");
82 return CMD_ERROR;
83 }
84
85 if (!protectedatoi(cargv[0], &startpoint)) {
86 chanservsendmessage(sender, "Error in starting day number.");
87 return CMD_ERROR;
88 }
89
90 if (startpoint<0) {
91 chanservsendmessage(sender, "Invalid starting day number.");
92 return CMD_ERROR;
93 }
94
95 if (startpoint>CSG_MAXSTARTPOINT) {
96 chanservsendmessage(sender, "Sorry, the maximum starting day is %d days.", CSG_MAXSTARTPOINT);
97 return CMD_ERROR;
98 }
99
710793ad
CP
100 chanservwallmessage("%s (%s) used RGREP %s %s", sender->nick, rup->username, cargv[0], cargv[1]);
101 cs_log(sender, "RGREP %s %s", cargv[0], cargv[1]);
102
107ccb4c
C
103 csg_curfile=startpoint;
104 csg_direction=1;
105 return csg_execgrep(sender, cargv[1]);
106}
107
108int csg_execgrep(nick *sender, char *pattern) {
109 const char *errptr;
110 int erroffset;
111 int fd;
112 char filename[50];
113
c86edd1d 114 if (csg_maxmatches>0) {
107ccb4c 115 chanservsendmessage(sender, "Sorry, the grepper is currently busy - try later.");
c86edd1d
Q
116 return CMD_ERROR;
117 }
118
107ccb4c 119 if (!(csg_curpat=pcre_compile(pattern, 0, &errptr, &erroffset, NULL))) {
c86edd1d
Q
120 chanservsendmessage(sender, "Error in pattern at character %d: %s",erroffset,errptr);
121 return CMD_ERROR;
122 }
123
107ccb4c
C
124 if (csg_direction==0 || csg_curfile==0) {
125 if ((fd=open("chanservlog",O_RDONLY))<0) {
126 chanservsendmessage(sender, "Unable to open logfile.");
127 free(csg_curpat);
128 return CMD_ERROR;
129 }
130 } else {
131 sprintf(filename,"chanservlog.%d",csg_curfile);
132 if ((fd=open(filename,O_RDONLY))<0) {
133 chanservsendmessage(sender, "Unable to open logfile.");
134 free(csg_curpat);
135 return CMD_ERROR;
136 }
c86edd1d
Q
137 }
138
139 /* Initialise stuff for the match */
140 csg_maxmatches=500;
141 csg_matches=0;
142 csg_curnum=sender->numeric;
c86edd1d 143 csg_bytesleft=0;
43583524 144 csg_bytesread=0;
c86edd1d
Q
145
146 registerhandler(fd, POLLIN, csg_handleevents);
107ccb4c 147 chanservsendmessage(sender, "Started grep for %s...",pattern);
c86edd1d
Q
148
149 return CMD_OK;
150}
151
152void csg_handleevents(int fd, short revents) {
153 int res;
154 nick *np=getnickbynumeric(csg_curnum);
155 char *chp, *linestart;
156 char filename[50];
157 off_t pos;
158
159 /* If the target user has vanished, drop everything */
160 if (!np) {
161 deregisterhandler(fd, 1);
162 free(csg_curpat);
163 csg_maxmatches=0;
164 return;
165 }
166
167retry:
168 res=read(fd, csg_readbuf+csg_bytesleft, CSG_BUFSIZE-csg_bytesleft);
169
170 if (res<=0) {
43583524 171/* chanservsendmessage(np, "Closing file: res=%d, errno=%d(%s), bytes read=%d",res,errno,sys_errlist[errno],csg_bytesread); */
c86edd1d
Q
172 /* End of file (or error) */
173 deregisterhandler(fd, 1);
107ccb4c
C
174 if (csg_direction==0) {
175 sprintf(filename,"chanservlog.%d",++csg_curfile);
176 } else {
177 csg_curfile--;
178 if (csg_curfile<0) {
179 chanservstdmessage(np, QM_ENDOFLIST);
9b9d3d58 180 free(csg_curpat);
181 csg_maxmatches=0;
107ccb4c
C
182 return;
183 } else if (csg_curfile==0) {
184 sprintf(filename,"chanservlog");
185 } else {
186 sprintf(filename,"chanservlog.%d",csg_curfile);
187 }
188 }
c86edd1d
Q
189 if ((fd=open(filename,O_RDONLY))>=0) {
190 /* Found the next file */
191 registerhandler(fd, POLLIN, csg_handleevents);
192 } else {
193 chanservstdmessage(np, QM_ENDOFLIST);
194 free(csg_curpat);
195 csg_maxmatches=0;
196 }
197
198 return;
199 }
200
43583524 201 csg_bytesread+=res;
202
c86edd1d
Q
203 linestart=chp=csg_readbuf;
204 csg_bytesleft+=res;
205
206 while (csg_bytesleft) {
207 csg_bytesleft--;
208 if (*chp=='\r' || *chp=='\n' || *chp=='\0') {
209 if (linestart==chp) {
210 linestart=(++chp);
211 } else {
212 *chp++='\0';
213 if (!pcre_exec(csg_curpat, NULL, linestart, strlen(linestart), 0, 0, NULL, 0)) {
214 chanservsendmessage(np, "%s", linestart);
215 if (++csg_matches >= csg_maxmatches) {
3a996626 216 chanservstdmessage(np, QM_TRUNCATED, csg_maxmatches);
c86edd1d
Q
217 chanservstdmessage(np, QM_ENDOFLIST);
218 free(csg_curpat);
219 deregisterhandler(fd, 1);
220 csg_maxmatches=0;
221 }
222 }
223 linestart=chp;
224 }
225 } else {
226 chp++;
227 }
228 }
229
230 csg_bytesleft=(chp-linestart);
231 memmove(csg_readbuf, linestart, csg_bytesleft);
232
233 /* BSD hack */
234 pos=lseek(fd, 0, SEEK_CUR);
235 if (!pread(fd, csg_readbuf+csg_bytesleft, 1, pos)) {
236 /* EOF */
237 goto retry;
238 }
239}