]> code.citadel.org Git - citadel.git/blob - citadel/stats.c
* Allow multiple simultaneous IPC connections. All changes necessary for
[citadel.git] / citadel / stats.c
1 /*
2  * $Id$
3  *
4  * Citadel/UX call log stats program
5  *
6  */
7
8 #include <stdlib.h>
9 #include <unistd.h>
10 #include <fcntl.h>
11
12 #if TIME_WITH_SYS_TIME
13 # include <sys/time.h>
14 # include <time.h>
15 #else
16 # if HAVE_SYS_TIME_H
17 #  include <sys/time.h>
18 # else
19 #  include <time.h>
20 # endif
21 #endif
22
23 #include <stdio.h>
24 #include <errno.h>
25 #include <string.h>
26 #include <limits.h>
27 #include "citadel.h"
28 #include "citadel_ipc.h"
29 #include "config.h"
30 #include "tools.h"
31
32 #define disply(x,y) printf("%20s            %4.1f    %4.1f    %4d\n",x,((float)y)/calls,((float)y)/days,y)
33
34 #define GRANULARITY 100
35
36 int batch_mode = 0;
37
38 struct caller {
39         struct caller *next;
40         char Cname[30];
41         int Ctimescalled;
42 };
43
44 void logoff(int code) {
45         exit(code);
46         }
47
48 void prompt(void)
49 {
50         char buf[16];
51         if (batch_mode == 0) {
52                 printf("Press return to continue...");
53                 fgets(buf, 16, stdin);
54         } else {
55                 printf("\n");
56         }
57 }
58
59 int halfhour(time_t time)
60 {                               /* Returns half-hour time period of time */
61         int a;
62         struct tm *tm;
63         tm = (struct tm *) localtime(&time);
64         a = (tm->tm_hour) * 3;
65         if ((tm->tm_min) > 19)
66                 ++a;
67         if ((tm->tm_min) > 39)
68                 ++a;
69         return (a);
70 }
71
72
73
74 void progress(long int curr, long int max)
75 {
76         static int dots;
77         int pos;
78
79         if (curr == 0L) {
80                 printf("--------------------------------------");
81                 printf("--------------------------------------\r");
82                 fflush(stdout);
83                 dots = 0;
84         }
85         pos = (curr * 72) / max;
86         while (dots < pos) {
87                 putc('*', stdout);
88                 fflush(stdout);
89                 ++dots;
90         }
91
92         if (dots == 72) {
93                 printf("                                      ");
94                 printf("                                      \r");
95                 fflush(stdout);
96         }
97 }
98
99
100
101
102 int main(int argc, char **argv)
103 {
104         char hostbuf[SIZ], portbuf[SIZ];
105         time_t LogTime, now;
106         unsigned int LogType;
107         char LogName[SIZ];
108         int a, b, lowest;
109         float p, q;
110         long timeon[72];
111         long timeup[72];
112         char dname[30];
113         int sess = 0;
114         long cftime, cttime, aa;
115         int calls, logins, newusers;
116         int badpws, terms, drops, sleeps;
117         time_t from, to, tottime;
118         int days, hours, minutes;
119         char aaa[100];
120         struct tm *tm;
121         struct caller *callers = NULL;
122         struct caller *callptr = NULL;
123         FILE *sortpipe;
124         char thegraph[GRANULARITY][73];
125         int pc_only = 0;
126         char buf[SIZ];
127         FILE *logfp;
128         char *fakeargs[4];
129         CtdlIPC *ipc = NULL;
130
131         for (a = 0; a < argc; ++a) {
132                 if (!strcmp(argv[a], "-b"))
133                         batch_mode = 1;
134                 if (!strcmp(argv[a], "-p"))
135                         pc_only = 1;
136         }
137
138
139         for (a = 0; a < GRANULARITY; ++a)
140                 strcpy(thegraph[a],
141                        "........................................................................");
142
143         get_config();
144         time(&now);
145
146         if (pc_only)
147                 goto PC_ONLY_HERE;
148
149         from = 0;
150         to = 0;
151         for (a = 0; a < 72; ++a) {
152                 timeon[a] = 0L;
153                 timeup[a] = 0L;
154         }
155         cftime = 0L;
156         cttime = 0L;
157
158         calls = 0;
159         logins = 0;
160         newusers = 0;
161         badpws = 0;
162         terms = 0;
163         drops = 0;
164         sleeps = 0;
165
166
167         logfp = fopen("citadel.log", "r");
168         if (logfp == NULL) {
169                 perror("Could not open citadel.log");
170                 exit(errno);
171         } else {
172                 if (!batch_mode) {
173                         printf("Scanning call log, please wait...\n");
174                 }
175                 while (fgets(buf, sizeof buf, logfp) != NULL) {
176                         buf[strlen(buf) - 1] = 0;
177                         strcat(buf, "| ");
178
179                         LogTime = atol(strtok(buf, "|"));
180                         LogType = atol(strtok(NULL, "|"));
181                         strcpy(LogName, strtok(NULL, "|"));
182
183                         if ( (LogType != 0) && (LogTime > 100L)
184                            && (LogTime <= now) ) {
185                                 if ((LogTime < from) || (from == 0L))
186                                         from = LogTime;
187                                 if ((LogTime > to) || (to == 0L))
188                                         to = LogTime;
189                                 strcpy(aaa, "");
190                                 if (LogType & CL_CONNECT) {
191                                         ++calls;
192                                         ++sess;
193                                         if (sess == 1)
194                                                 cftime = LogTime;
195                                         strcpy(dname, LogName);
196                                 }
197                                 if (LogType & CL_LOGIN) {
198                                         ++logins;
199                                         b = 0;
200                                         for (callptr = callers; callptr != NULL; callptr = callptr->next) {
201                                                 if (!strcmp(callptr->Cname, LogName)) {
202                                                         ++b;
203                                                         ++callptr->Ctimescalled;
204                                                 }
205                                         }
206                                         if (b == 0) {
207                                                 callptr = (struct caller *) malloc(sizeof(struct caller));
208                                                 callptr->next = callers;
209                                                 callers = callptr;
210                                                 strcpy(callers->Cname, LogName);
211                                                 callers->Ctimescalled = 1;
212                                         }
213                                 }
214                                 if (LogType & CL_NEWUSER)
215                                         ++newusers;
216                                 if (LogType & CL_BADPW)
217                                         ++badpws;
218                                 if (LogType & CL_TERMINATE) {
219                                         ++terms;
220                                         --sess;
221                                         if (sess == 0) {
222                                                 cttime = LogTime;
223                                                 for (aa = cftime; aa <= cttime; aa = aa + 300L)
224                                                         timeon[halfhour(aa)] = timeon[halfhour(aa)] + 5L;
225                                                 cftime = 0L;
226                                                 cttime = 0L;
227                                         }
228                                 }
229                                 if (LogType & CL_DROPCARR) {
230                                         ++drops;
231                                         --sess;
232                                         if (sess == 0) {
233                                                 cttime = LogTime;
234                                                 for (aa = cftime; aa <= cttime; aa = aa + 300L)
235                                                         timeon[halfhour(aa)] = timeon[halfhour(aa)] + 5L;
236                                                 cftime = 0L;
237                                                 cttime = 0L;
238                                         }
239                                 }
240                                 if (LogType & CL_SLEEPING) {
241                                         ++sleeps;
242                                         --sess;
243                                         if (sess == 0) {
244                                                 cttime = LogTime;
245                                                 for (aa = cftime; aa <= cttime; aa = aa + 300L)
246                                                         timeon[halfhour(aa)] = timeon[halfhour(aa)] + 5L;
247                                                 cftime = 0L;
248                                                 cttime = 0L;
249                                         }
250                                 }
251                                 if (sess < 0)
252                                         sess = 0;
253
254                         }
255                 }
256                 fclose(logfp);
257                 tottime = to - from;
258                 days = (int) (tottime / 86400L);
259                 hours = (int) ((tottime % 86400L) / 3600L);
260                 minutes = (int) ((tottime % 3600L) / 60L);
261
262                 printf("                              Avg/Call Avg/Day  Total\n");
263                 disply("Calls:", calls);
264                 disply("Logins:", logins);
265                 disply("New users:", newusers);
266                 disply("Bad pw attempts:", badpws);
267                 disply("Proper logoffs:", terms);
268                 disply("Carrier drops:", drops);
269                 disply("Sleeping drops:", sleeps);
270
271                 printf("\n");
272                 tm = (struct tm *) localtime(&from);
273                 printf("From:              %s", (char *) asctime(localtime(&from)));
274                 printf("To:                %s", (char *) asctime(localtime(&to)));
275                 printf("Total report time: ");
276                 printf("%d days, %d hours, %d minutes\n",
277                        days, hours, minutes);
278
279                 for (aa = from; aa <= to; aa = aa + 1200L)
280                         timeup[halfhour(aa)] = timeup[halfhour(aa)] + 20L;
281                 prompt();
282
283                 lowest = GRANULARITY - 1;
284                 for (b = 0; b < 72; ++b) {
285                         for (a = 0; a <= GRANULARITY; ++a) {
286                                 p = ((float) timeon[b]) / ((float) timeup[b]) * GRANULARITY;
287                                 q = (float) a;
288                                 if (p >= q) {
289                                         thegraph[(GRANULARITY - 1) - a][b] = '#';
290                                         if (lowest > (GRANULARITY - 1) - a)
291                                                 lowest = (GRANULARITY - 1) - a;
292                                 }
293                         }
294                 }
295
296                 printf("\n\n\n\n\n\n");
297
298                 b = ((GRANULARITY - lowest) / 18);
299                 if (b < 1)
300                         b = 1;
301                 for (a = lowest; a < GRANULARITY; a = a + b)
302                         printf("%2d%% |%s\n",
303                                100 - (a + 1),
304                                thegraph[a]);
305                 printf("    +------------------------------------------------------------------------\n");
306                 printf("     0  1  2  3  4  5  6  7  8  9  10 11 12 13 14 15 16 17 18 19 20 21 22 23\n");
307                 fflush(stdout);
308                 prompt();
309
310                 printf("\n\n\n\n");
311
312
313                 printf("Top 20 Callers (sorted by total number of logins)\n");
314                 printf("Calls Avg/Day Username\n");
315                 printf("----- ------- ------------------------------\n");
316                 fflush(stdout);
317                 sortpipe = (FILE *) popen("sort |tail -20 |sort -nr", "w");
318                 for (callptr = callers; callptr != NULL; callptr = callptr->next) {
319                         fprintf(sortpipe, "%5d %7.2f %-30s\n",
320                                 callptr->Ctimescalled,
321                                 (((float) callptr->Ctimescalled) / ((float) days)),
322                                 callptr->Cname);
323                 }
324                 pclose(sortpipe);
325                 while (callers != NULL) {
326                         callptr = callers->next;
327                         free(callers);
328                         callers = callptr;
329                 }
330                 prompt();
331
332               PC_ONLY_HERE:;    /* yes this semicolon is necessary; the DEC C compiler
333                                    complains that a label must be followed by an actual
334                                    statement. */
335
336
337                 printf("Top 20 Contributing Users (post to call ratio)\n");
338                 printf("P/C Ratio Username\n");
339                 printf("--------- ------------------------------\n");
340                 fflush(stdout);
341                 sortpipe = (FILE *) popen("sort |tail -20 |sort -nr", "w");
342
343
344
345                 fakeargs[0] = "whobbs";
346                 fakeargs[1] = "localhost";
347                 fakeargs[2] = malloc(64);
348                 snprintf(fakeargs[2], 64, "%d", config.c_port_number);
349                 fakeargs[3] = NULL;
350                 ipc = CtdlIPC_new(3, fakeargs, hostbuf, portbuf);
351                 free(fakeargs[2]);
352                 CtdlIPC_getline(ipc, buf);
353                 if ((buf[0]!='2')&&(strncmp(buf,"551",3))) {
354                         fprintf(stderr,"%s: %s\n",argv[0],&buf[4]);
355                 }
356                 else {
357                         CtdlIPC_putline(ipc, "LIST");
358                         CtdlIPC_getline(ipc, buf);
359                         if (buf[0]=='1') while (CtdlIPC_getline(ipc, buf), 
360                                                 strcmp(buf, "000")) {
361                                 extract(LogName, buf, 0);
362                                 fprintf(sortpipe, "%9.2f %-30s\n",
363                                         ((float) extract_int(buf,5) / (float) extract_int(buf,4)),
364                                         LogName);
365                         }
366                 }
367                 pclose(sortpipe);
368         }
369         return 0;
370 }