]> jfr.im git - irc/quakenet/newserv.git/blame - chanserv/chanservgrep.c
Add jupe support
[irc/quakenet/newserv.git] / chanserv / chanservgrep.c
CommitLineData
c86edd1d
Q
1
2#include "chanserv.h"
3#include "../core/events.h"
4#include <pcre.h>
5#include <sys/poll.h>
6#include <sys/types.h>
7#include <sys/stat.h>
8#include <fcntl.h>
9#include <unistd.h>
10#include <string.h>
11#include <stdio.h>
4ad1cf7a 12#include <unistd.h>
c86edd1d
Q
13
14#define CSG_BUFSIZE 512
15
16pcre *csg_curpat; /* Compiled pattern from pcre */
17int csg_curfile; /* Which logfile is being searched */
18unsigned long csg_curnum; /* What numeric is doing a search */
19int csg_matches; /* How many lines have been returned so far */
20int csg_maxmatches=0; /* How many matches are allowed */
21
22char csg_readbuf[CSG_BUFSIZE]; /* Buffer */
23int csg_bytesleft; /* How much valid data there is in the buffer */
24
25void csg_handleevents(int fd, short revents);
26int csg_dogrep(void *source, int cargc, char **cargv);
27
4ad1cf7a
CP
28#if !defined(pread)
29extern ssize_t pread(int fd, void *buf, size_t count, off_t offset);
30#endif
31
c86edd1d
Q
32void _init() {
33 chanservaddcommand("grep", QCMD_OPER, 1, csg_dogrep, "Searches the logs.");
34}
35
36void _fini() {
37 chanservremovecommand("grep", csg_dogrep);
38}
39
40int csg_dogrep(void *source, int cargc, char **cargv) {
41 nick *sender=source;
42 const char *errptr;
43 int erroffset;
44 int fd;
45
46 if (cargc<1) {
47 chanservstdmessage(sender, QM_NOTENOUGHPARAMS, "grep");
48 return CMD_ERROR;
49 }
50
51 if (csg_maxmatches>0) {
52 chanservsendmessage(sender, "Sorry, grep is currently busy - try later.");
53 return CMD_ERROR;
54 }
55
56 if (!(csg_curpat=pcre_compile(cargv[0], 0, &errptr, &erroffset, NULL))) {
57 chanservsendmessage(sender, "Error in pattern at character %d: %s",erroffset,errptr);
58 return CMD_ERROR;
59 }
60
61 if ((fd=open("chanservlog.0",O_RDONLY))<0) {
62 chanservsendmessage(sender, "Unable to open logfile.");
63 free(csg_curpat);
64 return CMD_ERROR;
65 }
66
67 /* Initialise stuff for the match */
68 csg_maxmatches=500;
69 csg_matches=0;
70 csg_curnum=sender->numeric;
71 csg_curfile=0;
72 csg_bytesleft=0;
73
74 registerhandler(fd, POLLIN, csg_handleevents);
75 chanservsendmessage(sender, "Started grep for %s...",cargv[0]);
76
77 return CMD_OK;
78}
79
80void csg_handleevents(int fd, short revents) {
81 int res;
82 nick *np=getnickbynumeric(csg_curnum);
83 char *chp, *linestart;
84 char filename[50];
85 off_t pos;
86
87 /* If the target user has vanished, drop everything */
88 if (!np) {
89 deregisterhandler(fd, 1);
90 free(csg_curpat);
91 csg_maxmatches=0;
92 return;
93 }
94
95retry:
96 res=read(fd, csg_readbuf+csg_bytesleft, CSG_BUFSIZE-csg_bytesleft);
97
98 if (res<=0) {
99 /* End of file (or error) */
100 deregisterhandler(fd, 1);
101 sprintf(filename,"chanservlog.%d",++csg_curfile);
102 if ((fd=open(filename,O_RDONLY))>=0) {
103 /* Found the next file */
104 registerhandler(fd, POLLIN, csg_handleevents);
105 } else {
106 chanservstdmessage(np, QM_ENDOFLIST);
107 free(csg_curpat);
108 csg_maxmatches=0;
109 }
110
111 return;
112 }
113
114 linestart=chp=csg_readbuf;
115 csg_bytesleft+=res;
116
117 while (csg_bytesleft) {
118 csg_bytesleft--;
119 if (*chp=='\r' || *chp=='\n' || *chp=='\0') {
120 if (linestart==chp) {
121 linestart=(++chp);
122 } else {
123 *chp++='\0';
124 if (!pcre_exec(csg_curpat, NULL, linestart, strlen(linestart), 0, 0, NULL, 0)) {
125 chanservsendmessage(np, "%s", linestart);
126 if (++csg_matches >= csg_maxmatches) {
127 chanservstdmessage(np, QM_ENDOFLIST);
128 free(csg_curpat);
129 deregisterhandler(fd, 1);
130 csg_maxmatches=0;
131 }
132 }
133 linestart=chp;
134 }
135 } else {
136 chp++;
137 }
138 }
139
140 csg_bytesleft=(chp-linestart);
141 memmove(csg_readbuf, linestart, csg_bytesleft);
142
143 /* BSD hack */
144 pos=lseek(fd, 0, SEEK_CUR);
145 if (!pread(fd, csg_readbuf+csg_bytesleft, 1, pos)) {
146 /* EOF */
147 goto retry;
148 }
149}