#define _LARGEFILE64_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef __APPLE__ #include #endif using namespace std; #define MAX_TOCC_INDEX 128 //#define _DEBUG #ifdef _DEBUG #define DEBUG(x) \ { \ x \ fflush(stdout); \ } while(0); #else #define DEBUG(x) #endif extern "C" { #include "io.h" #include "mem.h" #include "val.h" } #include "array.h" #include "br.h" #include "funcs.h" #include "main.h" void show_usage(void) { printf("Usage: mboxstats -i inputfile -o outputfile [-a] [-w] [-m] [-h]\n"); printf("-a show all data (not just the top 10)\n"); printf("-n x show top 'x' (default is 10)\n"); printf("-l lock mailbox\n"); printf("-x XML output\n"); printf("-z omit XML header\n"); printf("-y omit empty entries\n"); printf("-s x hide e-mail addresses [1=if name is know, 2=always]\n"); printf("-c also calculate number of bits information per byte\n"); printf("-m parameter for -i is a maildir\n"); printf("-p per-user statistics\n"); printf("-k abbreviate byte-amounts\n"); printf("-w count word-frequency (slows the program considerably down!)\n"); printf("-Q only for XML output! adds an url for from, to, cc and subject\n"); printf(" add '__REPLACE__' in the string which will get the from/etc.\n"); printf("-V show version\n"); printf("-h this message\n"); } char * to_xml_replace(char *in) { static char dummy[4096]; /* yes, I know */ int len = strlen(in); int index, oindex=0; for(index=0; index' || in[index] == '&' || in[index] == ' ') { sprintf(&dummy[oindex], "&#%d;", in[index]); oindex = strlen(dummy); } else dummy[oindex++] = in[index]; } dummy[oindex] = 0x00; return dummy; } char * hide_email_address(char *in, char hide) { /* really kids: you should not return pointers to static * buffers */ static char dummy[4096]; if (hide == 0) { return in; } if (in[0] == '"') strcpy(dummy, in + 1); else strcpy(dummy, in); char *lt = strchr(dummy, '<'); /* this will break on systems where NULL != 0 * and believe: those systems exist */ while(lt > dummy && (*lt == '<' || *lt == ' ' || *lt == '"')) { *lt = 0x00; --lt; } if ((hide == 1 && lt != NULL) || hide == 2) { char *at = strchr(dummy, '@'); if (at) { strcpy(at + 1, "xxx"); } } return dummy; } char * to_xml_tag(char *in) { static char dummy[4096]; int len = strlen(in); int index, oindex=0; if (isdigit(in[0])) { strcpy(dummy, "address-"); oindex = strlen(dummy); } for(index=0; index%s%s%s\n", searcher, url_escape(string), &repl[11]); free(searcher); return buffer; } char *b2kb(long unsigned int bytes, char abb) { /* FIXME: check for NULL and free() it after use (down there) */ char *buffer = (char *)mymalloc(64, "b2kb output"); if (!buffer) { fprintf(stderr, "out of memory\n"); exit(1); } if (abb) { if (bytes > (1024 * 1024 * 1024)) sprintf(buffer, "%ldGB", (bytes -1 + (1024 * 1024 * 1024)) / (1024 * 1024 * 1024)); else if (bytes > (1024 * 1024)) sprintf(buffer, "%ldMB", (bytes -1 + (1024 * 1024)) / (1024 * 1024)); else if (bytes > 1024) sprintf(buffer, "%ldKB", (bytes -1 + 1024) / 1024); else sprintf(buffer, "%ld", bytes); } else { sprintf(buffer, "%ld", bytes); } return buffer; } int main(int argc, char *argv[]) { /* statistics variables */ long unsigned int Cyear[3000]; // in the year 3000 this program will fail long unsigned int Cyearbytes[300]; long unsigned int Cmonth[12+1], Cday[31+1], Cwday[7+1], Chour[24], Ctotal=0, total=0; long unsigned int Cmonthbytes[12+1], Cdaybytes[31+1], Cwdaybytes[7+1], Chourbytes[24]; long unsigned int importance_low = 0, importance_normal = 0, importance_high = 0; long unsigned int total_lines = 0, total_header = 0; long unsigned int total_bytes = 0, total_header_bytes = 0; long unsigned int total_line_length = 0; char **MessageIDs = NULL; time_t *MessageIDst = NULL; int nMessageIDs = 0; struct tm first_tm; memset(&first_tm, 0x00, sizeof(first_tm)); first_tm.tm_sec = 59; first_tm.tm_min = 59; first_tm.tm_hour = 23; first_tm.tm_mday = 31; first_tm.tm_mon = 12 - 1; first_tm.tm_year = 2035 - 1900; time_t first_ts = mktime(&first_tm); time_t last_ts = 0; double total_bits = 0.0; char xml=0, xml_header=1; char he=0; char omit_empty=0; char abbr=0; int top_n = 10; double avg_spam_score = 0.0; int n_avg_spam_score = 0; char bits_per_byte = 0; char lock_file = 0; char calc_quote = 0; /* misc variables */ DIR *dir = NULL; FILE *fh; char empty_line = 0; int c; char *input = NULL, *output = NULL; char all = 0, cnt_words = 0; char peruser = 0; char mbox = 0; /* input is a mailbox-folder */ int lockfd = -1; time_t start, now; double fsize=0.0; /* double to prevent overflows */ /* msg-storage array */ char **msg = NULL; int msg_n = 0, msg_len = 0; char *searcher = NULL; memset(Cyear, 0x00, sizeof(Cyear)); memset(Cmonth, 0x00, sizeof(Cmonth)); memset(Cday, 0x00, sizeof(Cday)); memset(Cwday, 0x00, sizeof(Cwday)); memset(Chour, 0x00, sizeof(Chour)); memset(Cyearbytes, 0x00, sizeof(Cyearbytes)); memset(Cmonthbytes, 0x00, sizeof(Cmonthbytes)); memset(Cdaybytes, 0x00, sizeof(Cdaybytes)); memset(Cwdaybytes, 0x00, sizeof(Cwdaybytes)); memset(Chourbytes, 0x00, sizeof(Chourbytes)); if (argc == 1) { show_usage(); return 1; } /* parse parameters */ while((c = getopt(argc, argv, "i:o:l:awmphxzs:ykn:cqQ:")) != -1) { switch(c) { case 'i': input = optarg; break; case 'o': output = optarg; break; case 'a': all = 1; break; case 'q': calc_quote = 1; break; case 'l': lock_file = 1; break; case 'c': bits_per_byte = 1; break; case 'w': cnt_words = 1; break; case 'm': mbox = 1; break; case 'k': abbr = 1; break; case 'p': peruser = 1; break; case 'x': xml=1; break; case 'z': xml_header=0; break; case 's': he = atoi(optarg); if (he < 0 || he > 2) { fprintf(stderr, "-s parameter expects either 0, 1 or 2\n"); return 1; } break; case 'y': omit_empty=1; break; case 'n': top_n = atoi(optarg); if (top_n < 1) { fprintf(stderr, "number of elements to show must be at least 1 (and not %d)\n", top_n); return 1; } break; case 'Q': searcher = optarg; if (strstr(searcher, "__REPLACE__") == NULL) { fprintf(stderr, "Search-engine replace string misses '__REPLACE__'\n"); return 1; } break; case 'V': printf("mboxstats v" VERSION ", (C) 2003-2005 by folkert@vanheusden.com\n"); break; case 'h': show_usage(); exit(0); default: show_usage(); exit(0); } } /* lock file */ if (mbox == 0 && input != NULL && lock_file == 1) { lockfd = lockfile(input); if (lockfd == -1) { fprintf(stderr, "Cannot create lockfile!\n"); return 1; } } array from(13, 4); /* 0=hits, 1=bytes, 2=time, 3=n_lines/msg, 4=wday, 5=dmonth, 6=month, 7=linelength, 8=spam score, 9=# spam */ /* 10=n_replies_to + 11=replytime, 12=quote percentage */ /* subarray: 0 = useragent, 1=from (recv most msgs * from), 2=to (sent most msgs to), 3=subject */ array subject(5); /* 0=hits, 1=bytes, 2=time, 3=firstmsg, 4=lastmsg */ array to(3); /* 0=hits, 1=bytes, 2=time */ array cc(3); /* 0=hits, 1=bytes, 2=time */ array words(1); array tld(2); /* top level domains (0=hits, 1=bytes) */ array org(2); /* organization (0=hits, 1=bytes) */ array useragent(2); /* user-agent (0=hits, 1=bytes) */ array tz(2); /* timezone 0=hits, 1=bytes */ array bd(2); /* bussiest day 0=hits, 1=bytes */ array urls(1); int n_is_reply = 0; long int n_resp_time = 0; int global_is_reply = 0; int pgp_signed = 0; long long int total_att_size = 0; int n_att = 0; time(&start); for(;;) { int fd; char *file; struct dirent *de = NULL; char path[FILENAME_MAX]; DEBUG(printf("start\n");) /* not a mailbox-dir? then treat as file */ if (mbox == 0) { file = input; } else { /* mailbox-dir */ /* open directory */ if (!dir) { /* create path */ if (mbox == 1) sprintf(path, "%s/cur", input); else sprintf(path, "%s/new", input); if (output) printf("Processing path: %s\n", path); /* open directory */ dir = opendir(path); if (!dir) { fprintf(stderr, "Could not open directory %s!\n", path); if (mbox == 1) { mbox = 2; continue; } else { break; } } } /* try to fetch a file */ de = readdir(dir); if (!de) /* last file in dir, close dir */ { if (closedir(dir) == -1) { fprintf(stderr, "error closing director!\n"); break; } dir = NULL; /* both boxes done? exit */ if (mbox == 2) break; /* just did the cur-box, continue with the new-box */ mbox = 2; /* restart the loop */ continue; } /* create path */ if (mbox == 1) sprintf(path, "%s/cur/%s", input, de -> d_name); else sprintf(path, "%s/new/%s", input, de -> d_name); file = path; /* check for directories (skip them) */ struct stat st; if (stat(file, &st) == -1) /* file probably went away */ { if (errno == ENOENT) continue; fprintf(stderr, "problem fetching parameters on file %s!\n", file); return 1; } /* is dir? then skip */ if (S_ISDIR(st.st_mode)) continue; } DEBUG(printf("open file %s\n", file);) /* open the file */ if (file == NULL) fd = 0; else fd = open(file, O_RDONLY); if (fd == -1) { if (errno == ENOENT) /* file deleted? */ { fprintf(stderr, "file %s is not there!\n", file); break; /* continue */ } /* otherwhise: error situation */ fprintf(stderr, "error opening file %s\n", input); return 1; } /* get filesize */ if (fd != 0) { struct stat buf; if (fstat(fd, &buf) == -1) { fprintf(stderr, "error getting filesize: %s\n", strerror(errno)); return 1; } fsize = (double)buf.st_size; } /* start up buffered reader */ buffered_reader bf(fd); for(;;) { char *line; DEBUG(printf("read_line\n");) line = bf.read_line(); /* grow array if neccessary */ DEBUG(printf("resize\n");) if (resize((void **)&msg, msg_n, &msg_len, sizeof(char *)) == -1) { fprintf(stderr, "Memory allocation problem!\n"); break; } if (line != NULL && strlen(line) == 0) /* ignore empty lines */ { DEBUG(printf("ignore empty line\n");) empty_line = 1; msg[msg_n++] = NULL; free(line); } else if (line == NULL || (strncmp(line, "From ", 5) == 0 && empty_line == 1)) /* finished reading a message? */ { int year=0, month=0, day=0, wday=0, hour=0, minute=0, second=0; int from_index = -1, to_index[MAX_TOCC_INDEX], n_to_index=0, subject_index = -1; char *to_str[MAX_TOCC_INDEX]; int cc_index[MAX_TOCC_INDEX], n_cc_index=0; int loop, header_len = 0; unsigned long int msg_bytes = 0; char header = 1; char *fromfld = NULL; char *ua = NULL; char *subj = NULL; int add_org = -1; double spam_score = 0.0; char is_spam = 0; int cur_tz = -1; int cur_tld = -1; int cur_bd = -1; int cur_line_length = 0; time_t ts_t = (time_t)0; char *cur_msgid = NULL; char *in_reply_to = NULL; char *timezone = NULL; char *boundary = NULL; char msg_state = MS_TEXT; char interesting_attachment = 0; int quoted_lines = 0, original_lines = 0; char signature = 0; free(line); empty_line = 0; for(loop=0; loop<128; loop++) to_index[loop] = -1; /* keep track of total number of messages */ total++; /* end of message, process */ DEBUG(printf("end of msg, process\n");) for(loop=0; loop'); if (end) *end = 0x00; cur_tld = tld.addstring(dot + 1); } free(dummy); } else if (strncmp(msg[loop], "Message-ID:", 11) == 0) { char *dummy = strchr(&msg[loop][12], '<'); if (dummy) { cur_msgid = mystrdup(dummy); dummy = strchr(cur_msgid, '>'); if (dummy) *dummy = 0x00; } } else if (strncmp(msg[loop], "In-Reply-To:", 12) == 0) { char *dummy = strchr(&msg[loop][12], '<'); if (dummy) { in_reply_to = mystrdup(dummy); dummy = strchr(in_reply_to, '>'); if (dummy) *dummy = 0x00; } global_is_reply++; } else if (strncmp(msg[loop], "Subject:", 8) == 0) { subj = stripstring(&msg[loop][9]); subject_index = subject.addstring(subj); } else if (strncmp(msg[loop], "To:", 3) == 0) { char *dummy = stripstring(&msg[loop][4]); char *komma = strchr(dummy, ','); char *pnt = dummy; while (komma) { *komma = 0x00; to_index[n_to_index] = to.addstring(pnt, 1); to_str[n_to_index++] = mystrdup(pnt); pnt = komma + 1; while(*pnt == ' ') pnt++; komma = strchr(pnt, ','); } if (strlen(pnt) > 0) { to_index[n_to_index] = to.addstring(pnt, 1); to_str[n_to_index++] = mystrdup(pnt); } free(dummy); } else if (strncasecmp(msg[loop], "CC:", 3) == 0) { char *dummy = stripstring(&msg[loop][4]); char *komma = strchr(dummy, ','); char *pnt = dummy; while (komma) { *komma = 0x00; cc_index[n_cc_index++] = cc.addstring(pnt, 1); pnt = komma + 1; while(*pnt == ' ') pnt++; komma = strchr(pnt, ','); } if (strlen(pnt) > 0) cc_index[n_cc_index++] = cc.addstring(pnt, 1); free(dummy); } else if (strncmp(msg[loop], "Importance:", 11) == 0) { char *dummy = stripstring(&msg[loop][12]); if (strcasecmp(dummy, "Low") == 0) importance_low++; else if (strcasecmp(dummy, "Normal") == 0) importance_normal++; else if (strcasecmp(dummy, "High") == 0) importance_high++; free(dummy); } else if (strncmp(msg[loop], "Organization:", 13) == 0) { char *dummy = stripstring(&msg[loop][14]); add_org = org.addstring(dummy, 0); free(dummy); } else if (strncmp(msg[loop], "User-Agent:", 11) == 0) { char *dummy = stripstring(&msg[loop][12]); ua = mystrdup(&msg[loop][12]); free(dummy); } else if (strncmp(msg[loop], "X-Mailer:", 9) == 0) { char *dummy = stripstring(&msg[loop][10]); ua = mystrdup(&msg[loop][10]); free(dummy); } else if (strncmp(msg[loop], "X-Spam-Status:", 14) == 0) { /* X-Spam-Status: No, score=0.0 required=5.0 tests=HTML_MESSAGE autolearn=failed */ char *dummy = strstr(&msg[loop][14], "score="); if (dummy) { spam_score = atof(dummy + 6); avg_spam_score += spam_score; n_avg_spam_score++; char *req = strstr(&msg[loop][14], "required="); if (req) { if (spam_score >= atof(req + 9)) is_spam = 1; } } } else if ((bound_dum = strstr(msg[loop], " boundary=")) != NULL) { char *dummy = strchr(bound_dum, '"'); if (dummy) { int len = strlen(dummy + 1); boundary = (char *)mymalloc(len + 1, "boundary"); memcpy(boundary, dummy + 1, len); boundary[len] = 0x00; dummy = strchr(boundary, '"'); if (dummy) *dummy = 0x00; } else { bound_dum += 10; int len = strlen(bound_dum); boundary = (char *)mymalloc(len + 1, "boundary"); memcpy(boundary, bound_dum, len); boundary[len] = 0x00; dummy = strchr(boundary, ' '); if (dummy) *dummy = 0x00; dummy = strchr(boundary, '\t'); if (dummy) *dummy = 0x00; dummy = strchr(boundary, ';'); if (dummy) *dummy = 0x00; } } else if (strncmp(msg[loop], "Date:", 5) == 0) { char *dummy = stripstring(&msg[loop][6]); if (datestringtofields(dummy, year, month, day, wday, hour, minute, second, &timezone)) { if (month > 12 || day > 31 || wday > 7 || hour > 23 || year < 0) { if (output) printf("Invalid date-line: %s\n", &msg[loop][6]); month = day = wday = hour = 0; } else { struct tm ts; Cyear[year]++; Cmonth[month]++; Cday[day]++; Cwday[wday]++; Chour[hour]++; Ctotal++; memset(&ts, 0x00, sizeof(ts)); ts.tm_sec = second; ts.tm_min = minute; ts.tm_hour = hour; ts.tm_mday = day; ts.tm_mon = month - 1; ts.tm_year = year - 1900; ts_t = mktime(&ts); if (ts_t != (time_t)-1 && ts_t < first_ts) first_ts = ts_t; if (ts_t != (time_t)-1 && ts_t > last_ts) last_ts = ts_t; if (ts_t == (time_t)-1) ts_t = 0; /* bussiest day */ char buffer[128]; sprintf(buffer, "%04d-%02d-%02d", year, month, day); cur_bd = bd.addstring(buffer); } DEBUG(printf("add tz\n");) if (timezone) cur_tz = tz.addstring(timezone, 1); DEBUG(printf("tz done\n");) } free(dummy); } } else if (!signature) { if (msg[loop] != NULL) /* message-text */ { int len = strlen(msg[loop]); DEBUG(printf("do msg-text\n");) char *pnt; cur_line_length += len; pnt = msg[loop]; while((pnt = strstr(pnt, "http://"))) { char *end = strchr(pnt, ' '); if (end) *end = 0x00; else end = &pnt[strlen(pnt)]; urls.addstring(pnt); pnt = end + 1; } pnt = msg[loop]; while((pnt = strstr(pnt, "ftp://"))) { char *end = strchr(pnt, ' '); if (end) *end = 0x00; else end = &pnt[strlen(pnt)]; urls.addstring(pnt); pnt = end + 1; } if (strcmp(msg[loop], "--") == 0 || strcmp(msg[loop], "-- ") == 0) { signature = 1; } if (strncmp(msg[loop], "-----BEGIN PGP SIGNED MESSAGE-----", 34) == 0 || strncmp(msg[loop], "-----BEGIN PGP SIGNATURE-----", 29) == 0) { pgp_signed++; } /* determine if its quoted text or not */ pnt = msg[loop]; while(*pnt == ' ' || *pnt == '\t') pnt++; if (*pnt == '>') quoted_lines++; else original_lines++; /* start of mime thing? */ if (boundary != NULL && msg[loop][0] == '-' && msg[loop][1] == '-' && strcmp(&msg[loop][2], boundary) == 0) { if (msg_state == MS_DATA_LOOK) { // do anything? } msg_state = MS_HEADER; interesting_attachment = 0; } else if (msg_state == MS_HEADER) { // is a file-attachment? if (strstr(msg[loop], "filename=")) { interesting_attachment = 1; n_att++; } } else if (msg_state == MS_DATA_LOOK) { total_att_size += len; } if (cnt_words) { char *dummy = msg[loop]; for(;;) { char *end, stop=0; while(toupper(*dummy) < 'A' && toupper(*dummy) > 'Z' && *dummy != 0x00) dummy++; if (!*dummy) break; end = dummy; while(toupper(*end) >= 'A' && toupper(*end) <= 'Z' && *end != 0x00) { *end = tolower(*end); end++; } if (*end == 0x00) stop = 1; else *end = 0x00; if ((end-dummy) > 1 && (end-dummy) < 11) words.addstring(dummy); if (stop) break; dummy = end + 1; } } } else { if (interesting_attachment) msg_state = MS_DATA_LOOK; else msg_state = MS_DATA; } } else /* signature */ { } } DEBUG(printf("msg processed, overall stats\n");) total_bytes += msg_bytes; if (year >= 0 && year < 3000) Cyearbytes[year] += msg_bytes; Cmonthbytes[month] += msg_bytes; Cdaybytes[day] += msg_bytes; Cwdaybytes[wday] += msg_bytes; Chourbytes[hour] += msg_bytes; /* keep track of compose-time of each message */ if (ts_t != (time_t)0 && cur_msgid != NULL) { MessageIDs = (char **)myrealloc(MessageIDs, (nMessageIDs + 1) * sizeof(char *), "MessageIDs"); MessageIDs[nMessageIDs] = cur_msgid; MessageIDst = (time_t *)myrealloc(MessageIDst, (nMessageIDs + 1) * sizeof(time_t), "MessageIDs time_t"); if (timezone) MessageIDst[nMessageIDs++] = ts_t - (86400 * atoi(timezone) / 100); else MessageIDst[nMessageIDs++] = ts_t ; } if (add_org != -1) org.addcounter(add_org, 1, msg_bytes); if (cur_tz != -1) tz.addcounter(cur_tz, 1, msg_bytes); if (cur_tld != -1) tld.addcounter(cur_tld, 1, msg_bytes); if (cur_bd != -1) bd.addcounter(cur_bd, 1, msg_bytes); total_line_length += cur_line_length; /* per user number of bytes & time*/ DEBUG(printf("per user\n");) int time_index = (hour * 60) + minute; if (from_index != -1) { from.addcounter(from_index, 1, msg_bytes); from.addcounter(from_index, 2, time_index); from.addcounter(from_index, 3, msg_n - header_len); /* user-agent */ if (ua) { DEBUG(printf("user agent\n");) from.getsubcounter(from_index, 0).addstring(ua, 1); free(ua); } /* subject */ if (subj) { DEBUG(printf("subject\n");) from.getsubcounter(from_index, 3).addstring(subj, 1); free(subj); } from.addcounter(from_index, 4, wday); from.addcounter(from_index, 5, day); from.addcounter(from_index, 6, month); from.addcounter(from_index, 7, cur_line_length); from.addcounter(from_index, 8, (int)(spam_score * 1000.0)); if (is_spam) from.addcounter(from_index, 9, 1); if (in_reply_to) { int id_loop; if (ts_t != (time_t)0) { for(id_loop=0; id_loop 0) { DEBUG(printf("to stats\n");) for(int loop=0; loop %d\n", from_index);) if (from_index != -1) { from.getsubcounter(from_index, 2).addstring(to_str[loop], 1); } if (fromfld) { DEBUG(printf("%s %s\n", fromfld, to_str[loop]);) from.getsubcounter(to_str[loop], 1).addstring(fromfld, 1); } DEBUG(printf("-- 4\n");) free(to_str[loop]); } DEBUG(printf("-- 5\n");) free(fromfld); DEBUG(printf("-- 6\n");) } if (n_cc_index > 0) { DEBUG(printf("cc stats\n");) for(int loop=0; loop subject.getcounter(subject_index, 4)) subject.setcounter(subject_index, 4, ts_t); } } free_array((void ***)&msg, &msg_n, &msg_len); free(boundary); DEBUG(printf("done\n");) } else { empty_line = 0; msg[msg_n++] = line; } if (mbox == 0) { time(&now); if (unlikely((now - start) > 1)) { start = now; if (output && fd != 0) { printf("%3.2f%%\r", ((double)bf.file_offset() * 100.0) / fsize); fflush(stdout); } } } else { if (output) printf("%s \r", file); } if (!line) break; } close(fd); if (mbox == 0) break; } if (output) printf("Done parsing input file. Generating statistics...\n"); if (mbox == 0 && input != NULL && lock_file == 1) { if (unlockfile(input, lockfd) != 0) { fprintf(stderr, "Problem unlocking file!\nContinuing...\n"); } } if (output) fh = fopen(output, "w"); else fh = stdout; if (!fh) { fprintf(stderr, "Cannot create file %s!\n", output); return 1; } char *weekday[7+1] = { "", "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}; char *month[12+1] = { "", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; time(&now); int loop, more_then_1=0; for(loop=0; loop 1) more_then_1++; } /* for every user, find the most-used mail-client */ DEBUG(printf("top ua\n");) for(loop=0; loop highest_spam_score) { spammiest = loop; highest_spam_score = cur_score; } if (from.getcounter(loop, 9) > n_spams) { spammer = loop; n_spams = from.getcounter(loop, 9); } } if (from.getcounter(loop, 0)) { int dummy = from.getcounter(loop, 12) / from.getcounter(loop, 0); from.setcounter(loop, 12, dummy); qr_total += dummy; qr_n++; } } char *cur_time = mystrdup(ctime(&now)); char *lf = strchr(cur_time, '\n'); if (lf) *lf = 0x00; char *first_msg = mystrdup(ctime(&first_ts)); lf = strchr(first_msg, '\n'); if (lf) *lf = 0x00; char *last_msg = mystrdup(ctime(&last_ts)); lf = strchr(last_msg, '\n'); if (lf) *lf = 0x00; if (xml) { if (xml_header) fprintf(fh, "\n"); fprintf(fh, "\n"); fprintf(fh, " \n"); fprintf(fh, " %s\n", cur_time); fprintf(fh, " %s\n", first_msg); fprintf(fh, " %s\n", last_msg); fprintf(fh, " \n"); fprintf(fh, " %ld\n", total); fprintf(fh, " %d\n", global_is_reply); if (n_is_reply) { int avg_resp = n_resp_time / n_is_reply; fprintf(fh, " %02d:%02d:%02d\n", avg_resp / 3600, (avg_resp / 60) % 60, avg_resp % 60); } fprintf(fh, " %d\n", pgp_signed); fprintf(fh, " %s\n", b2kb(total_bytes, abbr)); fprintf(fh, " %s\n", b2kb(total_bytes / total, abbr)); fprintf(fh, " %d\n", n_att); fprintf(fh, " %s\n", b2kb(total_att_size, abbr)); if (calc_quote) fprintf(fh, " %.2f\n", (double)qr_total / (double)(qr_n * 10)); bd.sort(0); fprintf(fh, " %d%s\n", bd.getstring(0), bd.getcounter(0, 0), b2kb(bd.getcounter(0, 1), abbr)); bd.sort(1); fprintf(fh, " %d%s\n", bd.getstring(0), bd.getcounter(0, 0), b2kb(bd.getcounter(0, 1), abbr)); fprintf(fh, " %d\n", from.getN()); fprintf(fh, " %d\n", more_then_1); fprintf(fh, " %ld\n", total_lines); fprintf(fh, " %ld\n", total_header); fprintf(fh, " %d\n", useragent.getN()); fprintf(fh, " %d\n", org.getN()); fprintf(fh, " %d\n", tld.getN()); if (n_avg_spam_score) { fprintf(fh, " %f\n", avg_spam_score / ((double)n_avg_spam_score)); if (spammiest != -1) fprintf(fh, " %f%s\n", highest_spam_score, to_xml_replace(hide_email_address(from.getstring(spammiest), he))); if (spammer != -1) fprintf(fh, " %s\n", n_spams, to_xml_replace(hide_email_address(from.getstring(spammer), he))); } fprintf(fh, " \n"); fprintf(fh, " \n"); fprintf(fh, " %ld\n", total_lines / total); fprintf(fh, " %ld\n", total_header / total); fprintf(fh, " %.2f%%\n", ((double)total_header * 100.0) / (double)total_lines); fprintf(fh, " %.2f%%\n", ((double)total_header_bytes * 100.0) / (double)total_bytes); fprintf(fh, " %ld\n", total_line_length / total_lines); if (bits_per_byte) fprintf(fh, " %.4f\n", total_bits / (double)total_bytes); fprintf(fh, " \n"); if (total) { fprintf(fh, " \n"); fprintf(fh, " %.2f%%\n", ((double)importance_low * 100.0) / (double)total); fprintf(fh, " %.2f%%\n", ((double)importance_normal * 100.0) / (double)total); fprintf(fh, " %.2f%%\n", ((double)importance_high * 100.0) / (double)total); fprintf(fh, " \n"); } fprintf(fh, "\n"); fprintf(fh, " \n"); } else { fprintf(fh, "Overall statistics\n"); fprintf(fh, "------------------\n"); fprintf(fh, "Statistics created on: %s\n", cur_time); fprintf(fh, "First message was written at: %s\n", first_msg); fprintf(fh, "Last message was written at: %s\n", last_msg); fprintf(fh, "Total number of messages: %ld\n", total); fprintf(fh, "Number of messages that is a reply: %d (%.2f%%)\n", global_is_reply, (double)(global_is_reply * 100) / (double)total); fprintf(fh, "Total size: %s\n", b2kb(total_bytes, abbr)); fprintf(fh, "Average size: %s\n", b2kb(total_bytes / total, abbr)); fprintf(fh, "Total number of attachments: %d\n", n_att); fprintf(fh, "Total size of attachments: %s (%.2f%% of total)\n", b2kb(total_att_size, abbr), (total_att_size * 100.0) / ((double)total_bytes)); if (calc_quote) fprintf(fh, "Average quote percentage: %.2f%%\n", (double)qr_total / (double)(qr_n * 10)); if (n_is_reply) { int avg_resp = n_resp_time / n_is_reply; fprintf(fh, "Average response time: %02d:%02d:%02d\n", avg_resp / 3600, (avg_resp / 60) % 60, avg_resp % 60); } fprintf(fh, "Number of PGP signed messages: %d (%.2f%%)\n", pgp_signed, ((double)pgp_signed * 100.0) / total); bd.sort(0); fprintf(fh, "Most busy day in # msgs: %s (%d msgs, %s bytes)\n", bd.getstring(0), bd.getcounter(0, 0), b2kb(bd.getcounter(0, 1), abbr)); bd.sort(1); fprintf(fh, "Most busy day in # bytes: %s (%d msgs, %s bytes)\n", bd.getstring(0), bd.getcounter(0, 0), b2kb(bd.getcounter(0, 1), abbr)); fprintf(fh, "Total number of writers: %d\n", from.getN()); fprintf(fh, "Number of people who wrote >1 message: %d (%.2f%%)\n", more_then_1, (double)(more_then_1 * 100) / (double)from.getN()); fprintf(fh, "Total number of lines: %ld\n", total_lines); if (total) fprintf(fh, "Average lines per message: %ld\n", total_lines / total); fprintf(fh, "Total header length (lines): %ld\n", total_header); if (total) fprintf(fh, "Average header length (lines): %ld (%.2f%%)\n", total_header / total, (double)(total_header * 100) / (double)total_lines); if (total_lines) fprintf(fh, "Average line length: %ld\n", total_line_length / total_lines); if (total_bytes) fprintf(fh, "The header is %.2f%% bytes in size of the total.\n", ((double)total_header_bytes * 100.0) / (double)total_bytes); if (bits_per_byte) { if (total_bytes) fprintf(fh, "Average number of bits information per byte: %.4f\n", total_bits / (double)total_bytes); } fprintf(fh, "Total number of unique user-agents: %d\n", useragent.getN()); fprintf(fh, "Total number of unique organisations: %d\n", org.getN()); fprintf(fh, "Total number of unique top-level domains: %d\n", tld.getN()); if (n_avg_spam_score) { fprintf(fh, "Average spam score: %.2f\n", avg_spam_score / ((double)n_avg_spam_score)); if (spammiest != -1) fprintf(fh, "Spammiest writer: %s (%.2f)\n", hide_email_address(from.getstring(spammiest), he), highest_spam_score); if (spammer != -1) fprintf(fh, "Most spam by: %s (%d)\n", hide_email_address(from.getstring(spammer), he), n_spams); } fprintf(fh, "\n"); if (total) { DEBUG(printf("importance\n");) fprintf(fh, "Importance\n"); fprintf(fh, "----------\n"); fprintf(fh, "Low : %.2f%%\n", ((double)importance_low * 100.0) / (double)total); fprintf(fh, "Normal: %.2f%%\n", ((double)importance_normal * 100.0) / (double)total); fprintf(fh, "High : %.2f%%\n", ((double)importance_high * 100.0) / (double)total); fprintf(fh, "(the rest is unspecified)\n"); } fprintf(fh, "\n"); } DEBUG(printf("top writers\n");) if (xml) fprintf(fh, " \n"); else { fprintf(fh, "Top writers\n"); fprintf(fh, " | # msgs|av size| total|time | e-mail address\n"); fprintf(fh, "---+-------+-------+------+-----+--------------------------------\n"); } from.sort(0); for(loop=0; loop<(all?from.getN():top_n); loop++) { char *string = from.getstring(loop); if (!string) break; if (from.getcounter(loop, 0)) { int dummy = from.getcounter(loop, 2) / from.getcounter(loop, 0); if (xml) { fprintf(fh, " \n", loop+1); fprintf(fh, " %s\n", to_xml_replace(hide_email_address(string, he))); fprintf(fh, "%s", emit_url(searcher, string)); fprintf(fh, " %d\n", from.getcounter(loop, 0)); fprintf(fh, " %s\n", b2kb(from.getcounter(loop, 1) / from.getcounter(loop, 0), abbr)); fprintf(fh, " %s\n", b2kb(from.getcounter(loop, 1), abbr)); fprintf(fh, " %02d:%02d\n", dummy/60, dummy%60); fprintf(fh, " \n"); } else fprintf(fh, "%3d] %6d|%7s|%6s|%02d:%02d| %s\n", loop+1, from.getcounter(loop, 0), b2kb(from.getcounter(loop, 1) / from.getcounter(loop, 0), abbr), b2kb(from.getcounter(loop, 1), abbr), (dummy / 60), (dummy % 60), hide_email_address(string, he)); } else if (!xml) fprintf(fh, "%3d] %6d| | %s\n", loop+1, from.getcounter(loop, 0), hide_email_address(string, he)); } if (xml) fprintf(fh, " \n"); else fprintf(fh, "\n"); DEBUG(printf("top subjects\n");) if (xml) fprintf(fh, " \n"); else { fprintf(fh, "Top subjects\n"); fprintf(fh, " | # msgs|av size| total|time | subject\n"); fprintf(fh, "---+-------+-------+------+-----+--------------------------------\n"); } subject.sort(0); for(loop=0; loop<(all?subject.getN():top_n); loop++) { char *string = subject.getstring(loop); if (!string) break; if (subject.getcounter(loop, 0)) { int dummy = subject.getcounter(loop, 2) / subject.getcounter(loop, 0); if (xml) { fprintf(fh, " \n", loop+1); fprintf(fh, " %s\n", to_xml_replace(string)); fprintf(fh, "%s", emit_url(searcher, string)); fprintf(fh, " %d\n", subject.getcounter(loop, 0)); fprintf(fh, " %s\n", b2kb(subject.getcounter(loop, 1) / subject.getcounter(loop, 0), abbr)); fprintf(fh, " %s\n", b2kb(subject.getcounter(loop, 1), abbr)); fprintf(fh, " %02d:%02d\n", dummy/60, dummy%60); fprintf(fh, " %d\n", subject.getcounter(loop, 3)); fprintf(fh, " %d\n", subject.getcounter(loop, 4)); fprintf(fh, " \n"); } else fprintf(fh, "%3d] %6d|%7s|%6s|%02d:%02d| %s\n", loop+1, subject.getcounter(loop, 0), b2kb(subject.getcounter(loop, 1) / subject.getcounter(loop, 0), abbr), b2kb(subject.getcounter(loop, 1), abbr), (dummy / 60), (dummy % 60), hide_email_address(string, he)); } else if (!xml) fprintf(fh, "%3d] %6d| | %s\n", loop+1, subject.getcounter(loop, 0), hide_email_address(string, he)); } if (xml) fprintf(fh, " \n"); else fprintf(fh, "\n"); DEBUG(printf("top receivers\n");) if (xml) fprintf(fh, " \n"); else { fprintf(fh, "Top receivers\n"); fprintf(fh, " | # msgs|av size| total|time | e-mail address\n"); fprintf(fh, "---+-------+-------+------+-----+--------------------------------\n"); } to.sort(0); for(loop=0; loop<(all?to.getN():top_n); loop++) { char *string = to.getstring(loop); if (!string) break; if (to.getcounter(loop, 0)) { int dummy = to.getcounter(loop, 2) / to.getcounter(loop, 0); if (xml) { fprintf(fh, " \n", loop+1); fprintf(fh, " %s\n", to_xml_replace(hide_email_address(string, he))); fprintf(fh, "%s", emit_url(searcher, string)); fprintf(fh, " %d\n", to.getcounter(loop, 0)); fprintf(fh, " %s\n", b2kb(to.getcounter(loop, 1) / to.getcounter(loop, 0), abbr)); fprintf(fh, " %s\n", b2kb(to.getcounter(loop, 1), abbr)); fprintf(fh, " %02d:%02d\n", dummy/60, dummy%60); fprintf(fh, " \n"); } else fprintf(fh, "%3d] %6d|%7s|%6s|%02d:%02d| %s\n", loop+1, to.getcounter(loop, 0), b2kb(to.getcounter(loop, 1) / to.getcounter(loop, 0), abbr), b2kb(to.getcounter(loop, 1), abbr), (dummy / 60), (dummy % 60), hide_email_address(string, he)); } else if (!xml) fprintf(fh, "%3d] %6d| | %s\n", loop+1, to.getcounter(loop, 0), hide_email_address(string, he)); } if (xml) fprintf(fh, " \n"); else fprintf(fh, "\n"); if (cc.getN()) { DEBUG(printf("top ccers\n");) if (xml) fprintf(fh, " \n"); else { fprintf(fh, "Top CC'ers\n"); fprintf(fh, " | # msgs|av size| total|time | e-mail address\n"); fprintf(fh, "---+-------+-------+------+-----+--------------------------------\n"); } cc.sort(0); for(loop=0; loop<(all?cc.getN():top_n); loop++) { char *string = cc.getstring(loop); if (!string) break; if (cc.getcounter(loop, 0)) { int dummy = cc.getcounter(loop, 2) / cc.getcounter(loop, 0); if (xml) { fprintf(fh, " \n", loop+1); fprintf(fh, " %s\n", to_xml_replace(hide_email_address(string, he))); fprintf(fh, "%s", emit_url(searcher, string)); fprintf(fh, " %d\n", cc.getcounter(loop, 0)); fprintf(fh, " %s\n", b2kb(cc.getcounter(loop, 1) / cc.getcounter(loop, 0), abbr)); fprintf(fh, " %s\n", b2kb(cc.getcounter(loop, 1), abbr)); fprintf(fh, " %02d:%02d\n", dummy/60, dummy%60); fprintf(fh, " \n"); } else fprintf(fh, "%3d] %6d|%7s|%6s|%02d:%02d| %s\n", loop+1, cc.getcounter(loop, 0), b2kb(cc.getcounter(loop, 1) / cc.getcounter(loop, 0), abbr), b2kb(cc.getcounter(loop, 1), abbr), (dummy / 60), (dummy % 60), hide_email_address(string, he)); } else if (!xml) fprintf(fh, "%3d] %6d| | %s\n", loop+1, cc.getcounter(loop, 0), hide_email_address(string, he)); } if (xml) fprintf(fh, " \n"); else fprintf(fh, "\n"); } DEBUG(printf("top tld\n");) if (xml) fprintf(fh, " \n"); else { fprintf(fh, "Top of top-level-domain\n"); fprintf(fh, " |tld | KB/MB | n\n"); fprintf(fh, "---+----+--------+----------------------------------------\n"); } tld.sort(0); for(loop=0; loop<(all?tld.getN():top_n); loop++) { char *string = tld.getstring(loop); if (!string) break; if (xml) { if ((omit_empty && strlen(string) > 0) || omit_empty == 0) { fprintf(fh, " \n", loop + 1); fprintf(fh, " %s\n", to_xml_replace(string)); fprintf(fh, " %d\n", tld.getcounter(loop, 0)); fprintf(fh, " %s\n", b2kb(tld.getcounter(loop, 1) / tld.getcounter(loop, 0), abbr)); fprintf(fh, " %s\n", b2kb(tld.getcounter(loop, 1), abbr)); fprintf(fh, " \n"); } } else fprintf(fh, "%2d] %4s (%6s) %d\n", loop+1, string, b2kb(tld.getcounter(loop, 1), abbr), tld.getcounter(loop, 0)); } if (xml) fprintf(fh, " \n"); else fprintf(fh, "\n"); if (tz.getN()) { DEBUG(printf("top timezone\n");) if (xml) fprintf(fh, " \n"); else { fprintf(fh, "Timezones\n"); fprintf(fh, " | n | KB/MB |tld\n"); fprintf(fh, "---+----+--------+----------------------------------------\n"); } tz.sort(0); for(loop=0; loop<(all?tz.getN():top_n); loop++) { char *string = tz.getstring(loop); if (!string) break; if (xml) { if ((omit_empty && strlen(string) > 0) || omit_empty == 0) { fprintf(fh, " \n", loop + 1); fprintf(fh, " %s\n", to_xml_replace(string)); fprintf(fh, " %d\n", tz.getcounter(loop, 0)); fprintf(fh, " %s\n", b2kb(tz.getcounter(loop, 1) / tz.getcounter(loop, 0), abbr)); fprintf(fh, " %s\n", b2kb(tz.getcounter(loop, 1), abbr)); fprintf(fh, " \n"); } } else fprintf(fh, "%2d] %4d (%6s) %s\n", loop+1, tz.getcounter(loop, 0), b2kb(tz.getcounter(loop, 1), abbr), string); } if (xml) fprintf(fh, " \n"); else fprintf(fh, "\n"); } if (org.getN()) { DEBUG(printf("top org\n");) if (xml) fprintf(fh, " \n"); else { fprintf(fh, "Top organisations\n"); fprintf(fh, " | n | KB/MB | Organisation\n"); fprintf(fh, "---+----+--------+----------------------------------------\n"); } org.sort(0); for(loop=0; loop<(all?org.getN():top_n); loop++) { char *string = org.getstring(loop); if (!string) break; if (xml) { if ((omit_empty && strlen(string) > 0) || omit_empty == 0) { fprintf(fh, " \n", loop + 1); fprintf(fh, " %s\n", to_xml_replace(string)); fprintf(fh, " %d\n", org.getcounter(loop, 0)); fprintf(fh, " %s\n", b2kb(org.getcounter(loop, 1), abbr)); fprintf(fh, " \n"); } } else fprintf(fh, "%2d] %4d (%6s) %s\n", loop+1, org.getcounter(loop, 0), b2kb(org.getcounter(loop, 1), abbr), string); } if (xml) fprintf(fh, " \n"); else fprintf(fh, "\n"); } /* useragents */ if (useragent.getN()) { if (xml) fprintf(fh, " \n"); else { fprintf(fh, "Top user agents\n"); fprintf(fh, "(number of unique user agents, NOT the amount of messages per user agent)\n"); fprintf(fh, " | n | KB/MB |User agent\n"); fprintf(fh, "---+----+--------+----------------------------------------\n"); } useragent.sort(0); for(loop=0; loop<(all?useragent.getN():top_n); loop++) { char *string = useragent.getstring(loop); if (!string) break; if (xml) { if ((omit_empty && strlen(string) > 0) || omit_empty == 0) { fprintf(fh, " \n", loop + 1); fprintf(fh, " %s\n", to_xml_replace(string)); fprintf(fh, " %d\n", useragent.getcounter(loop, 0)); fprintf(fh, " %s\n", b2kb(useragent.getcounter(loop, 1), abbr)); fprintf(fh, " \n"); } } else fprintf(fh, "%2d] %4d (%6s) %s\n", loop+1, useragent.getcounter(loop, 0), b2kb(useragent.getcounter(loop, 1), abbr), string); } if (xml) fprintf(fh, " \n"); else fprintf(fh, "\n"); fflush(fh); } if (Ctotal) { DEBUG(printf("top mpm\n");) long unsigned int max_day = 0; for(loop=1; loop<=7; loop++) max_day = max(Cwday[loop], max_day); DEBUG(printf("max/day: %ld\n", max_day);) if (xml) fprintf(fh, " \n"); else { fprintf(fh, "Messages per day\n"); fprintf(fh, "----------------------------------------------------------\n"); } for(loop=1; loop<=7; loop++) { if (xml) fprintf(fh, " <%s>%ld%s\n", weekday[loop], Cwday[loop], b2kb(Cwdaybytes[loop], abbr), weekday[loop]); else { fprintf(fh, "%9s %5ld (%6s)", weekday[loop], Cwday[loop], b2kb(Cwdaybytes[loop], abbr)); for(int loop2=0; loop2<(double(Cwday[loop]) * (32.0 / double(max_day))); loop2++) fprintf(fh, "*"); fprintf(fh, "\n"); } } if (xml) fprintf(fh, " \n"); else fprintf(fh, "\n"); fflush(fh); long unsigned int max_year = 0; for(loop=0; loop<3000; loop++) max_year = max(Cyear[loop], max_year); DEBUG(printf("max/year: %ld\n", max_year);) if (xml) fprintf(fh, " \n"); else { fprintf(fh, "Messages per year\n"); fprintf(fh, "----------------------------------------------------------\n"); } loop=0; while(Cyear[loop] == 0 && loop < 3000) loop++; int loop_end=2999; while(Cyear[loop_end] == 0 && loop_end > 0) loop_end--; loop_end++; for(; loop<=loop_end; loop++) { if (xml) fprintf(fh, " %ld%s\n", loop, Cyear[loop], b2kb(Cyearbytes[loop], abbr), loop); else { fprintf(fh, "%d %5ld (%6s)", loop, Cyear[loop], b2kb(Cyearbytes[loop], abbr)); for(int loop2=0; loop2<(double(Cyear[loop]) * (39.0 / double(max_year))); loop2++) fprintf(fh, "*"); fprintf(fh, "\n"); } } if (xml) fprintf(fh, " \n"); else fprintf(fh, "\n"); fflush(fh); long unsigned int max_month = 0; for(loop=1; loop<=12; loop++) max_month = max(Cmonth[loop], max_month); DEBUG(printf("max/month: %ld\n", max_month);) if (xml) fprintf(fh, " \n"); else { fprintf(fh, "Messages per month\n"); fprintf(fh, "----------------------------------------------------------\n"); } for(loop=1; loop<=12; loop++) { if (xml) fprintf(fh, " <%s>%ld%s\n", month[loop], Cmonth[loop], b2kb(Cmonthbytes[loop], abbr), month[loop]); else { fprintf(fh, "%s %5ld (%6s)", month[loop], Cmonth[loop], b2kb(Cmonthbytes[loop], abbr)); for(int loop2=0; loop2<(double(Cmonth[loop]) * (39.0 / double(max_month))); loop2++) fprintf(fh, "*"); fprintf(fh, "\n"); } } if (xml) fprintf(fh, " \n"); else fprintf(fh, "\n"); fflush(fh); if (xml) fprintf(fh, " \n"); else { fprintf(fh, "Messages per day-of-the-month\n"); fprintf(fh, "----------------------------------------------------------\n"); } long unsigned int max_dmonth = 0; for(loop=1; loop<=31; loop++) max_dmonth = max(Cday[loop], max_dmonth); DEBUG(printf("max/dmonth: %ld\n", max_dmonth);) for(loop=1; loop<=31; loop++) { if (xml) fprintf(fh, " %ld%s\n", loop, Cday[loop], b2kb(Cdaybytes[loop], abbr), loop); else { fprintf(fh, "%2d %5ld (%6s)", loop, Cday[loop], b2kb(Cdaybytes[loop], abbr)); for(int loop2=0; loop2<(double(Cday[loop]) * (39.0 / double(max_day))); loop2++) fprintf(fh, "*"); fprintf(fh, "\n"); } } if (xml) fprintf(fh, " \n"); else fprintf(fh, "\n"); fflush(fh); if (xml) fprintf(fh, " \n"); else { fprintf(fh, "Messages per hour\n"); fprintf(fh, "----------------------------------------------------------\n"); } long unsigned int max_hour = 0; for(loop=1; loop<=23; loop++) max_hour = max(Chour[loop], max_hour); DEBUG(printf("max/hour: %ld\n", max_hour);) for(loop=1; loop<=23; loop++) { if (xml) fprintf(fh, " %ld%s\n", loop, Chour[loop], b2kb(Chourbytes[loop], abbr), loop); else { fprintf(fh, "%2d %5ld (%6s)", loop, Chour[loop], b2kb(Chourbytes[loop], abbr)); for(int loop2=0; loop2<(double(Chour[loop]) * (40.0 / double(max_hour))); loop2++) fprintf(fh, "*"); fprintf(fh, "\n"); } } if (xml) fprintf(fh, " \n"); else fprintf(fh, "\n"); fflush(fh); } if (cnt_words) { DEBUG(printf("top words\n");) if (xml) fprintf(fh, " \n"); else { fprintf(fh, "Most used words\n"); fprintf(fh, " |count | word\n"); fprintf(fh, "-----+------+---------------------------\n"); } words.sort(0); for(loop=0; loop<(all?words.getN():top_n); loop++) { char *string = words.getstring(loop); if (!string) break; if (xml) fprintf(fh, " <%s>%d\n", string, words.getcounter(loop, 0), string); else fprintf(fh, "%5d] %5d| %s\n", loop+1, words.getcounter(loop, 0), string); } if (xml) fprintf(fh, " \n"); else fprintf(fh, "\n"); fflush(fh); } if (urls.getN()) { if (xml) fprintf(fh, " \n"); else { fprintf(fh, "URLs\n"); fprintf(fh, " | n | URL\n"); fprintf(fh, "---+-----+------------------------------------------------\n"); } urls.sort(0); for(loop=0; loop<(all?urls.getN():top_n); loop++) { char *dummy = urls.getstring(loop); if (!dummy) break; if (xml) fprintf(fh, " %d%s\n", loop+1, urls.getcounter(loop, 0), to_xml_replace(dummy), loop + 1); else fprintf(fh, "%2d] %5d %s\n", loop+1, urls.getcounter(loop, 0), dummy); } if (xml) fprintf(fh, " \n"); else fprintf(fh, "\n"); fflush(fh); } /* to quick replyers */ array avg_resp(2); for(loop=0; loop\n"); else { fprintf(fh, "Top quick replyers\n"); fprintf(fh, " |interval| n | URL\n"); fprintf(fh, "---+--------+-----+------------------------------------------\n"); } avg_resp.sort(0); for(loop=avg_resp.getN()-1; loop>=(all?0:max(0,avg_resp.getN()-(1 + top_n))); loop--) { int cur_avg_resp = avg_resp.getcounter(loop, 0); char *string = avg_resp.getstring(loop); if (!string) break; if (xml) { fprintf(fh, " \n", n_done); fprintf(fh, " %s\n", to_xml_replace(hide_email_address(avg_resp.getstring(loop), he))); fprintf(fh, " %02d:%02d:%02d\n", cur_avg_resp / 3600, (cur_avg_resp / 60) % 60, cur_avg_resp % 60); fprintf(fh, " %d\n", avg_resp.getcounter(loop, 1)); fprintf(fh, " \n"); } else fprintf(fh, "%2d] %02d:%02d:%02d (%3d) %s\n", n_done, cur_avg_resp / 3600, (cur_avg_resp / 60) % 60, cur_avg_resp % 60, avg_resp.getcounter(loop, 1), hide_email_address(string, he)); n_done++; } if (xml) fprintf(fh, " \n"); else fprintf(fh, "\n"); fflush(fh); } if (calc_quote) { if (xml) fprintf(fh, " \n"); else { fprintf(fh, "Top quoters\n"); fprintf(fh, " |Perc. | n | Who\n"); fprintf(fh, "---+------+-----+-----------------------------------------\n"); } from.sort(12); for(loop=0; loop<(all?from.getN():top_n); loop++) { char *string = from.getstring(loop); if (!string) break; if (xml) { fprintf(fh, " \n", loop + 1); fprintf(fh, " %s\n", to_xml_replace(hide_email_address(string, he))); fprintf(fh, " %d\n", from.getcounter(loop, 0)); fprintf(fh, " %.2f%%\n", (double)from.getcounter(loop, 12) / 10.0); fprintf(fh, " \n"); } else fprintf(fh, "%2d] %3.2f%% (%3d) %s\n", loop + 1, (double)from.getcounter(loop, 12) / 10.0, from.getcounter(loop, 0), hide_email_address(string, he)); } if (xml) fprintf(fh, " \n"); else fprintf(fh, "\n"); fflush(fh); } if (peruser) { DEBUG(printf("top per-user\n");) if (xml) fprintf(fh, " \n"); else { fprintf(fh, "Per-user statistics\n"); fprintf(fh, "----------------------------------------------------------\n"); } for(loop=0; loop\n"); fprintf(fh, " %s\n", to_xml_replace(hide_email_address(from.getstring(loop), he))); } else fprintf(fh, "Stats for %s\n", hide_email_address(from.getstring(loop), he)); if (from.getcounter(loop, 0)) { if (xml) { fprintf(fh, " %d\n", from.getcounter(loop, 0)); if (from.getcounter(loop, 10)) fprintf(fh, " %d\n", from.getcounter(loop, 11) / from.getcounter(loop, 10)); fprintf(fh, " %s\n", b2kb(from.getcounter(loop, 1), abbr)); fprintf(fh, " %s\n", b2kb(from.getcounter(loop, 1) / div, abbr)); fprintf(fh, " %02d:%02d\n", dummy / 60, dummy % 60); fprintf(fh, " %s\n", weekday[from.getcounter(loop, 4) / div]); fprintf(fh, " %d\n", from.getcounter(loop, 5) / div); fprintf(fh, " %s\n", month[from.getcounter(loop, 6) / div]); } else { fprintf(fh, "# msgs: %d, total # bytes: %s, avg # bytes: %s, time: %02d:%02d, # lines/msg: %d\n", from.getcounter(loop, 0), b2kb(from.getcounter(loop, 1), abbr), b2kb(from.getcounter(loop, 1) / div, abbr), (dummy / 60), (dummy % 60), from.getcounter(loop, 3) / div ); fprintf(fh, "Most active week-day: %s, day-of-month: %d, month: %s\n", weekday[from.getcounter(loop, 4) / div], from.getcounter(loop, 5) / div, month[from.getcounter(loop, 6) / div]); if (from.getcounter(loop, 10)) { int avg_resp = from.getcounter(loop, 11) / from.getcounter(loop, 10); fprintf(fh, "Average response time: %02d:%02d:%02d\n", avg_resp / 3600, (avg_resp / 60) % 60, avg_resp % 60); } } if (from.getcounter(loop, 3)) { if (xml) fprintf(fh, " %d\n", from.getcounter(loop, 7) / from.getcounter(loop, 3)); else fprintf(fh, "Avg. line length: %d\n", from.getcounter(loop, 7) / from.getcounter(loop, 3)); } if (n_avg_spam_score) { if (xml) { fprintf(fh, " %f\n", from.getcounter(loop, 8) / (double)(from.getcounter(loop, 0) * 1000)); fprintf(fh, " %d\n", from.getcounter(loop, 9)); } else { fprintf(fh, "Avg. spam score: %.3f, # spam messages: %d\n", from.getcounter(loop, 8) / (double)(from.getcounter(loop, 0) * 1000), from.getcounter(loop, 9)); } } } if (from.getsubcounter(loop, 0).getN()) { from.getsubcounter(loop, 0).sort(0); /* useragent */ if (xml) fprintf(fh, " \n %s\n %d\n \n", to_xml_replace(from.getsubcounter(loop, 0).getstring(0)), from.getsubcounter(loop, 0).getcounter(0, 0)); else fprintf(fh, "Most used useragent : %s (%d)\n", from.getsubcounter(loop, 0).getstring(0), from.getsubcounter(loop, 0).getcounter(0, 0)); } if (from.getsubcounter(loop, 1).getN()) { from.getsubcounter(loop, 1).sort(0); /* from (most recv msgs from) */ if (xml) fprintf(fh, " \n %s\n %d\n \n", to_xml_replace(hide_email_address(from.getsubcounter(loop, 1).getstring(0), he)), from.getsubcounter(loop, 1).getcounter(0, 0)); else fprintf(fh, "Most msgs received from: %s (%d)\n", hide_email_address(from.getsubcounter(loop, 1).getstring(0), he), from.getsubcounter(loop, 1).getcounter(0, 0)); } if (from.getsubcounter(loop, 2).getN()) { from.getsubcounter(loop, 2).sort(0); /* to (most msgs sent to) */ if (xml) fprintf(fh, " \n %s\n %d\n \n", to_xml_replace(hide_email_address(from.getsubcounter(loop, 2).getstring(0), he)), from.getsubcounter(loop, 2).getcounter(0, 0)); else fprintf(fh, "Most msgs sent to : %s (%d)\n", hide_email_address(from.getsubcounter(loop, 2).getstring(0), he), from.getsubcounter(loop, 2).getcounter(0, 0)); } if (from.getsubcounter(loop, 3).getN()) { from.getsubcounter(loop, 3).sort(0); /* most used subject */ if (xml) fprintf(fh, " \n %s\n %d\n \n", to_xml_replace(from.getsubcounter(loop, 3).getstring(0)), from.getsubcounter(loop, 3).getcounter(0, 0)); else fprintf(fh, "Most used subject : %s (%d)\n", from.getsubcounter(loop, 3).getstring(0), from.getsubcounter(loop, 3).getcounter(0, 0)); } if (xml) fprintf(fh, " \n"); else fprintf(fh, "----------------------------------------------------------\n"); } if (xml) fprintf(fh, " \n"); else fprintf(fh, "\n"); fflush(fh); } if (xml) { fprintf(fh, " mboxstats" VERSION "folkert@vanheusden.comhttp://www.vanheusden.com/mboxstats/\n"); fprintf(fh, "\n"); } else { fprintf(fh, "Created with mboxstats v" VERSION "; written by folkert@vanheusden.com\n"); fprintf(fh, "http://www.vanheusden.com/mboxstats/\n"); } DEBUG(printf("finished\n");) fclose(fh); if (output) printf("Done\n"); return 0; }