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