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