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