]> jfr.im git - irc/quakenet/newserv.git/blob - chanserv/chanservgrep.c
Added some log rotation support and other tweaks.
[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 1024
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 int csg_bytesread;
22
23 char csg_readbuf[CSG_BUFSIZE]; /* Buffer */
24 int csg_bytesleft; /* How much valid data there is in the buffer */
25
26 void csg_handleevents(int fd, short revents);
27 int csg_dogrep(void *source, int cargc, char **cargv);
28
29 #if !defined(pread)
30 extern ssize_t pread(int fd, void *buf, size_t count, off_t offset);
31 #endif
32
33 void _init() {
34 chanservaddcommand("grep", QCMD_OPER, 1, csg_dogrep, "Searches the logs.","");
35 }
36
37 void _fini() {
38 chanservremovecommand("grep", csg_dogrep);
39 }
40
41 int csg_dogrep(void *source, int cargc, char **cargv) {
42 nick *sender=source;
43 const char *errptr;
44 int erroffset;
45 int fd;
46
47 if (cargc<1) {
48 chanservstdmessage(sender, QM_NOTENOUGHPARAMS, "grep");
49 return CMD_ERROR;
50 }
51
52 if (csg_maxmatches>0) {
53 chanservsendmessage(sender, "Sorry, grep is currently busy - try later.");
54 return CMD_ERROR;
55 }
56
57 if (!(csg_curpat=pcre_compile(cargv[0], 0, &errptr, &erroffset, NULL))) {
58 chanservsendmessage(sender, "Error in pattern at character %d: %s",erroffset,errptr);
59 return CMD_ERROR;
60 }
61
62 if ((fd=open("chanservlog",O_RDONLY))<0) {
63 chanservsendmessage(sender, "Unable to open logfile.");
64 free(csg_curpat);
65 return CMD_ERROR;
66 }
67
68 /* Initialise stuff for the match */
69 csg_maxmatches=500;
70 csg_matches=0;
71 csg_curnum=sender->numeric;
72 csg_curfile=0;
73 csg_bytesleft=0;
74 csg_bytesread=0;
75
76 registerhandler(fd, POLLIN, csg_handleevents);
77 chanservsendmessage(sender, "Started grep for %s...",cargv[0]);
78
79 return CMD_OK;
80 }
81
82 void csg_handleevents(int fd, short revents) {
83 int res;
84 nick *np=getnickbynumeric(csg_curnum);
85 char *chp, *linestart;
86 char filename[50];
87 off_t pos;
88
89 /* If the target user has vanished, drop everything */
90 if (!np) {
91 deregisterhandler(fd, 1);
92 free(csg_curpat);
93 csg_maxmatches=0;
94 return;
95 }
96
97 retry:
98 res=read(fd, csg_readbuf+csg_bytesleft, CSG_BUFSIZE-csg_bytesleft);
99
100 if (res<=0) {
101 /* chanservsendmessage(np, "Closing file: res=%d, errno=%d(%s), bytes read=%d",res,errno,sys_errlist[errno],csg_bytesread); */
102 /* End of file (or error) */
103 deregisterhandler(fd, 1);
104 sprintf(filename,"chanservlog.%d",++csg_curfile);
105 if ((fd=open(filename,O_RDONLY))>=0) {
106 /* Found the next file */
107 registerhandler(fd, POLLIN, csg_handleevents);
108 } else {
109 chanservstdmessage(np, QM_ENDOFLIST);
110 free(csg_curpat);
111 csg_maxmatches=0;
112 }
113
114 return;
115 }
116
117 csg_bytesread+=res;
118
119 linestart=chp=csg_readbuf;
120 csg_bytesleft+=res;
121
122 while (csg_bytesleft) {
123 csg_bytesleft--;
124 if (*chp=='\r' || *chp=='\n' || *chp=='\0') {
125 if (linestart==chp) {
126 linestart=(++chp);
127 } else {
128 *chp++='\0';
129 if (!pcre_exec(csg_curpat, NULL, linestart, strlen(linestart), 0, 0, NULL, 0)) {
130 chanservsendmessage(np, "%s", linestart);
131 if (++csg_matches >= csg_maxmatches) {
132 chanservstdmessage(np, QM_ENDOFLIST);
133 free(csg_curpat);
134 deregisterhandler(fd, 1);
135 csg_maxmatches=0;
136 }
137 }
138 linestart=chp;
139 }
140 } else {
141 chp++;
142 }
143 }
144
145 csg_bytesleft=(chp-linestart);
146 memmove(csg_readbuf, linestart, csg_bytesleft);
147
148 /* BSD hack */
149 pos=lseek(fd, 0, SEEK_CUR);
150 if (!pread(fd, csg_readbuf+csg_bytesleft, 1, pos)) {
151 /* EOF */
152 goto retry;
153 }
154 }