]>
Commit | Line | Data |
---|---|---|
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 | |
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 */ | |
107ccb4c | 23 | int csg_direction; /* Log direction (0 = forward, 1 = reverse) */ |
43583524 | 24 | int csg_bytesread; |
c86edd1d Q |
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); | |
107ccb4c C |
31 | int csg_dorgrep(void *source, int cargc, char **cargv); |
32 | int csg_execgrep(nick *sender, char *pattern); | |
c86edd1d | 33 | |
4ad1cf7a CP |
34 | #if !defined(pread) |
35 | extern ssize_t pread(int fd, void *buf, size_t count, off_t offset); | |
36 | #endif | |
37 | ||
c86edd1d | 38 | void _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 | ||
43 | void _fini() { | |
44 | chanservremovecommand("grep", csg_dogrep); | |
107ccb4c | 45 | chanservremovecommand("rgrep", csg_dorgrep); |
c86edd1d Q |
46 | } |
47 | ||
48 | int csg_dogrep(void *source, int cargc, char **cargv) { | |
49 | nick *sender=source; | |
c86edd1d Q |
50 | |
51 | if (cargc<1) { | |
52 | chanservstdmessage(sender, QM_NOTENOUGHPARAMS, "grep"); | |
53 | return CMD_ERROR; | |
54 | } | |
55 | ||
107ccb4c C |
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 | ||
c86edd1d | 96 | if (csg_maxmatches>0) { |
107ccb4c | 97 | chanservsendmessage(sender, "Sorry, the grepper is currently busy - try later."); |
c86edd1d Q |
98 | return CMD_ERROR; |
99 | } | |
100 | ||
107ccb4c | 101 | if (!(csg_curpat=pcre_compile(pattern, 0, &errptr, &erroffset, NULL))) { |
c86edd1d Q |
102 | chanservsendmessage(sender, "Error in pattern at character %d: %s",erroffset,errptr); |
103 | return CMD_ERROR; | |
104 | } | |
105 | ||
107ccb4c C |
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 | } | |
c86edd1d Q |
119 | } |
120 | ||
121 | /* Initialise stuff for the match */ | |
122 | csg_maxmatches=500; | |
123 | csg_matches=0; | |
124 | csg_curnum=sender->numeric; | |
c86edd1d | 125 | csg_bytesleft=0; |
43583524 | 126 | csg_bytesread=0; |
c86edd1d Q |
127 | |
128 | registerhandler(fd, POLLIN, csg_handleevents); | |
107ccb4c | 129 | chanservsendmessage(sender, "Started grep for %s...",pattern); |
c86edd1d Q |
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) { | |
43583524 | 153 | /* chanservsendmessage(np, "Closing file: res=%d, errno=%d(%s), bytes read=%d",res,errno,sys_errlist[errno],csg_bytesread); */ |
c86edd1d Q |
154 | /* End of file (or error) */ |
155 | deregisterhandler(fd, 1); | |
107ccb4c C |
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); | |
9b9d3d58 | 162 | free(csg_curpat); |
163 | csg_maxmatches=0; | |
107ccb4c C |
164 | return; |
165 | } else if (csg_curfile==0) { | |
166 | sprintf(filename,"chanservlog"); | |
167 | } else { | |
168 | sprintf(filename,"chanservlog.%d",csg_curfile); | |
169 | } | |
170 | } | |
c86edd1d Q |
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 | ||
43583524 | 183 | csg_bytesread+=res; |
184 | ||
c86edd1d Q |
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) { | |
3a996626 | 198 | chanservstdmessage(np, QM_TRUNCATED, csg_maxmatches); |
c86edd1d Q |
199 | chanservstdmessage(np, QM_ENDOFLIST); |
200 | free(csg_curpat); | |
201 | deregisterhandler(fd, 1); | |
202 | csg_maxmatches=0; | |
203 | } | |
204 | } | |
205 | linestart=chp; | |
206 | } | |
207 | } else { | |
208 | chp++; | |
209 | } | |
210 | } | |
211 | ||
212 | csg_bytesleft=(chp-linestart); | |
213 | memmove(csg_readbuf, linestart, csg_bytesleft); | |
214 | ||
215 | /* BSD hack */ | |
216 | pos=lseek(fd, 0, SEEK_CUR); | |
217 | if (!pread(fd, csg_readbuf+csg_bytesleft, 1, pos)) { | |
218 | /* EOF */ | |
219 | goto retry; | |
220 | } | |
221 | } |