]> jfr.im git - irc/quakenet/newserv.git/blob - chanserv/chanservgrep.c
Add jupe support
[irc/quakenet/newserv.git] / chanserv / chanservgrep.c
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>
12 #include <unistd.h>
13
14 #define CSG_BUFSIZE 512
15
16 pcre *csg_curpat; /* Compiled pattern from pcre */
17 int csg_curfile; /* Which logfile is being searched */
18 unsigned long csg_curnum; /* What numeric is doing a search */
19 int csg_matches; /* How many lines have been returned so far */
20 int csg_maxmatches=0; /* How many matches are allowed */
21
22 char csg_readbuf[CSG_BUFSIZE]; /* Buffer */
23 int csg_bytesleft; /* How much valid data there is in the buffer */
24
25 void csg_handleevents(int fd, short revents);
26 int csg_dogrep(void *source, int cargc, char **cargv);
27
28 #if !defined(pread)
29 extern ssize_t pread(int fd, void *buf, size_t count, off_t offset);
30 #endif
31
32 void _init() {
33 chanservaddcommand("grep", QCMD_OPER, 1, csg_dogrep, "Searches the logs.");
34 }
35
36 void _fini() {
37 chanservremovecommand("grep", csg_dogrep);
38 }
39
40 int 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
80 void 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
95 retry:
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 }