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