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