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