]>
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> |
5857b2db P |
14 | #include "../lib/version.h" |
15 | ||
16 | MODULE_VERSION(QVERSION) | |
c86edd1d | 17 | |
43583524 | 18 | #define CSG_BUFSIZE 1024 |
71c362ef | 19 | #define CSG_MAXSTARTPOINT 30 |
c86edd1d Q |
20 | |
21 | pcre *csg_curpat; /* Compiled pattern from pcre */ | |
22 | int csg_curfile; /* Which logfile is being searched */ | |
23 | unsigned long csg_curnum; /* What numeric is doing a search */ | |
24 | int csg_matches; /* How many lines have been returned so far */ | |
25 | int csg_maxmatches=0; /* How many matches are allowed */ | |
107ccb4c | 26 | int csg_direction; /* Log direction (0 = forward, 1 = reverse) */ |
43583524 | 27 | int csg_bytesread; |
c86edd1d Q |
28 | |
29 | char csg_readbuf[CSG_BUFSIZE]; /* Buffer */ | |
30 | int csg_bytesleft; /* How much valid data there is in the buffer */ | |
31 | ||
32 | void csg_handleevents(int fd, short revents); | |
33 | int csg_dogrep(void *source, int cargc, char **cargv); | |
107ccb4c C |
34 | int csg_dorgrep(void *source, int cargc, char **cargv); |
35 | int csg_execgrep(nick *sender, char *pattern); | |
c86edd1d | 36 | |
4ad1cf7a CP |
37 | #if !defined(pread) |
38 | extern ssize_t pread(int fd, void *buf, size_t count, off_t offset); | |
39 | #endif | |
40 | ||
c86edd1d | 41 | void _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 | ||
46 | void _fini() { | |
47 | chanservremovecommand("grep", csg_dogrep); | |
107ccb4c | 48 | chanservremovecommand("rgrep", csg_dorgrep); |
c86edd1d Q |
49 | } |
50 | ||
51 | int 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 | ||
72 | int 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 | ||
108 | int 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 | ||
152 | void 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 | ||
167 | retry: | |
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 | } |