]> jfr.im git - irc/quakenet/newserv.git/blob - chanprofile/chanprofile.c
A4STATS: remove E style escapes and switch to createtable for indices
[irc/quakenet/newserv.git] / chanprofile / chanprofile.c
1
2 #include "chanprofile.h"
3 #include "../channel/channel.h"
4 #include "../control/control.h"
5 #include "../newsearch/newsearch.h"
6 #include "../lib/version.h"
7
8 MODULE_VERSION("");
9
10 #include <stdio.h>
11 #include <string.h>
12 #include <stdlib.h>
13
14 unsigned int activeprofiles;
15 struct chanprofile *cptable[CPHASHSIZE];
16
17 struct chanprofile *getcprec(nick *np) {
18 unsigned int hash=0,mhash;
19 unsigned int ccount=0;
20 unsigned int clen=0;
21 unsigned int i;
22 struct chanprofile *cpp;
23
24 struct channel **cs=(np->channels->content);
25
26 ccount=np->channels->cursi;
27
28 for (i=0;i<np->channels->cursi;i++) {
29 clen+=cs[i]->index->name->length;
30 hash ^= (unsigned long)cs[i];
31 }
32
33 mhash=hash%CPHASHSIZE;
34
35 for (cpp=cptable[mhash];cpp;cpp=cpp->next) {
36 if ((cpp->hashval==hash) && (cpp->ccount==ccount) &&
37 (cpp->clen==clen))
38 return cpp;
39 }
40
41 cpp=malloc(sizeof(struct chanprofile));
42
43 cpp->clones=0;
44 cpp->hashval=hash;
45 cpp->ccount=ccount;
46 cpp->clen=clen;
47 cpp->nicks=NULL;
48 cpp->next=cptable[mhash];
49 cptable[mhash]=cpp;
50
51 activeprofiles++;
52
53 return cpp;
54 }
55
56 void popprofiles() {
57 unsigned int i;
58 struct chanprofile *cpp;
59 nick *np;
60
61 /* Create the chanprofile records and count clones for each profile */
62 for (i=0;i<NICKHASHSIZE;i++) {
63 for (np=nicktable[i];np;np=np->next) {
64 cpp=getcprec(np);
65 cpp->clones++;
66 }
67 }
68
69 /* Allocate space for nick array in each profile */
70 for (i=0;i<CPHASHSIZE;i++) {
71 for (cpp=cptable[i];cpp;cpp=cpp->next) {
72 cpp->nicks=(nick **)malloc(cpp->clones * sizeof(nick *));
73 cpp->clones=0;
74 }
75 }
76
77 /* Populate the nick arrays */
78 for (i=0;i<NICKHASHSIZE;i++) {
79 for (np=nicktable[i];np;np=np->next) {
80 cpp=getcprec(np);
81 cpp->nicks[cpp->clones++]=np;
82 }
83 }
84 }
85
86 void clearprofiles() {
87 unsigned int i;
88 struct chanprofile *cpp, *ncpp;
89
90 for (i=0;i<CPHASHSIZE;i++) {
91 for (cpp=cptable[i];cpp;cpp=ncpp) {
92 ncpp=cpp->next;
93 free(cpp->nicks);
94 free(cpp);
95 }
96 cptable[i]=NULL;
97 }
98
99 activeprofiles=0;
100 }
101
102 int cpcompare(const void *a, const void *b) {
103 const struct chanprofile **cpa=(const struct chanprofile **)a, **cpb=(const struct chanprofile **)b;
104
105 return (*cpb)->clones - (*cpa)->clones;
106 }
107
108 void reportprofile(nick *sender, struct chanprofile *cpp) {
109 channel **cps, *cp;
110 unsigned int i;
111 nick *np;
112 char buf[1024];
113 unsigned int repwidth=80;
114 unsigned int bufpos;
115 searchCtx ctx;
116
117 controlreply(sender,"============================================================");
118
119 if (cpp->ccount==0) {
120 controlreply(sender,"(no channels): %u users",cpp->clones);
121 return;
122 }
123
124 controlreply(sender,"Channels (%u):",cpp->ccount);
125
126 np=cpp->nicks[0];
127 cps=np->channels->content;
128 bufpos=0;
129 for (i=0;i<np->channels->cursi;i++) {
130 cp=cps[i];
131 if (bufpos && ((bufpos + cp->index->name->length) > repwidth)) {
132 controlreply(sender," %s",buf);
133 bufpos=0;
134 }
135
136 bufpos += sprintf(buf+bufpos,"%s ",cp->index->name->content);
137 }
138
139 if (bufpos)
140 controlreply(sender," %s",buf);
141
142 controlreply(sender,"Users (%u):",cpp->clones);
143
144 ctx.reply = controlreply;
145 for (i=0;i<cpp->clones;i++) {
146 printnick(&ctx, sender,cpp->nicks[i]);
147 }
148 }
149
150 int reportprofiles(void *source, int cargc, char **cargv) {
151 unsigned int i,j;
152 struct chanprofile **cpary, *cpp;
153 unsigned int repnum=20;
154 nick *sender=source;
155
156 if (cargc>0)
157 repnum=strtoul(cargv[0],NULL,10);
158
159 popprofiles();
160
161 /* Make a big fat array */
162 cpary=malloc(activeprofiles*sizeof(struct chanprofile *));
163 for (i=0,j=0;i<CPHASHSIZE;i++)
164 for (cpp=cptable[i];cpp;cpp=cpp->next)
165 cpary[j++]=cpp;
166
167 controlreply(sender,"Populated array, lest number=%u (should be %u)",j,activeprofiles);
168
169 qsort(cpary, activeprofiles, sizeof(struct chanprofile *), cpcompare);
170
171 controlreply(sender,"Top %u channel profiles (%u total):",repnum,activeprofiles);
172
173 for (i=0;i<repnum;i++) {
174 reportprofile(sender,cpary[i]);
175 }
176
177 free(cpary);
178
179 controlreply(sender,"--- End of list.");
180
181 clearprofiles();
182
183 return CMD_OK;
184 }
185
186 void _init() {
187 memset(cptable,0,sizeof(cptable));
188 registercontrolhelpcmd("chanprofiles",NO_DEVELOPER,1,reportprofiles,"Usage: chanprofiles [count]\nDisplays the most common channel profiles. count defaults to 20.");
189 }
190
191 void _fini() {
192 deregistercontrolcmd("chanprofiles",reportprofiles);
193 }
194