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