Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > alt.os.linux.slackware > #35613

countmail.py

From jayjwa <jayjwa@atr2.ath.cx.invalid>
Newsgroups alt.os.linux.slackware
Subject countmail.py
Date 2026-06-01 22:54 -0400
Organization atr2net 2026
Message-ID <87mrxdzm6p.fsf@atr2.ath.cx> (permalink)

Show all headers | View raw


Following the discussion of it on LQ, I re-wrote BSD countmail because
that script is a bit bristly, requires eternal tools like "frm", and
doesn't handle Alpine/Pine's placeholder messages properly. This
version uses ANSI colors and works on SunOS too.

#!/usr/bin/python3
## countmail.py
## Rewrite of BSD countmail in basic Python to not use external tools
## and correctly handle Al/pine placeholder mails. Cross-platform for
## Linux, SunOS, probably others with Python3.
## $Id: countmail.py,v 1.1 2026/06/02 02:28:57 jayjwa Exp $
import os, sys, re

# ANSI color codes. 
RED='\033[0;31m'
GREEN='\033[0;32m'
BLUE='\033[0;34m'
NC='\033[0m'

# Convert a number to its word equivalent. Handles up to 1 trillion.
def integerToWords( num ):
    # dict to match an integer to its word value
    d = { 0 : 'zero', 1 : 'one', 2 : 'two', 3 : 'three', 4 : 'four',
          5 : 'five', 6 : 'six', 7 : 'seven', 8 : 'eight', 9 : 'nine',
          10 : 'ten', 11 : 'eleven', 12 : 'twelve', 13 : 'thirteen',
          14 : 'fourteen', 15 : 'fifteen', 16 : 'sixteen',
          17 : 'seventeen', 18 : 'eighteen', 19 : 'nineteen',
          20 : 'twenty', 30 : 'thirty', 40 : 'forty', 50 : 'fifty',
          60 : 'sixty', 70 : 'seventy', 80 : 'eighty', 90 : 'ninety'
         }
    
    # thousands, millions, billions, trillions
    k = 1000
    m = k * 1000
    b = m * 1000
    t = b * 1000

    # Shouldn't happen since there's no such thing as negative mail counts
    if num < 0:
        return d[ 0 ]

    # Likewise
    if num > 1000000000000:
        # You don't really have that much mail...
        sys.exit( f"{RED}You have too much mail!{NC}" )
    
    # Recursively check the number, based on its size. Return the dict
    # entry for that integer number.
    if ( num < 20 ):
        return d[ num ]
    
    if ( num < 100 ):
        if num % 10 == 0:
            return d[ num ]
        else:
            return d[ num // 10 * 10 ] + '-' + d[ num % 10 ]
        
    if ( num < k ):
        if num % 100 == 0:
            return d[ num // 100 ] + ' hundred'
        else:
            return d[ num // 100 ] + ' hundred and ' + integerToWords(num % 100)

    if ( num < m ):
        if num % k == 0:
            return integerToWords( num // k ) + ' thousand'
        else:
            return integerToWords( num // k ) + ' thousand, ' + integerToWords( num % k )

    if ( num < b ):
        if ( num % m ) == 0:
            return integerToWords( num // m ) + ' million'
        else:
            return integerToWords( num // m ) + ' million, ' + integerToWords( num % m )

    if ( num < t ):
        if ( num % b ) == 0:
            return integerToWords( num // b ) + ' billion'
        else:
            return integerToWords( num // b ) + ' billion, ' + integerToWords( num % b )

    if ( num % t == 0 ):
        return integerToWords( num // t ) + ' trillion'
    else:
        return integerToWords( num // t ) + ' trillion, ' + integerToWords( num % t )

    
# First, locate the user's mail file. Respect env var, then search filesys.
mailfile = os.getenv( 'MAIL' )
if not mailfile:
    # Try to construct a path to a mail file. LOGNAME is consistent
    # across Linux and SunOS. Do not use "USER". Check popular places
    # but don't go crazy digging for it.
    if os.path.isfile( f"/var/mail/{os.getenv( 'LOGNAME' )}" ):
        mailfile = f"/var/mail/{os.getenv( 'LOGNAME' )}"
    elif os.path.isfile( f"/var/spool/mail/{os.getenv( 'LOGNAME' )}" ):
        mailfile = f"/var/spool/mail/{os.getenv( 'LOGNAME' )}"
    else:
        # Still nothing? We can't work with no mail file.
        sys.exit( f"{RED}Can't locate a mail file on this system!{NC}" )
    
# Regex to indicate that there is a mail message in the mail file. MUAs
# like Alpine and Pine have a placeholder message that must be excluded
# from the total count because it is not a real mail message.
mailPattern = re.compile( r'^From: *[^Mail System Internal Data]' )
count = 0

# Assume mailPattern is a mail occurance and count them
with open( mailfile, 'r' ) as mf:
    for line in mf:
        if re.match( mailPattern, line ):
            count += 1

# "One" is singular, use "s" for the rest
if count == 1:
    suffix = ""
else:
    suffix = "s"

# This is the original display format for BSD countmail. More or less. 
print( f"{GREEN}{ integerToWords( count ).upper() }!{NC}\n\n{GREEN}{ integerToWords( count ).capitalize() } mail message{suffix}!{NC}" )
print( f"{BLUE}HaHaHaHaHa!{NC}" )

## EOF

-- 
PGP Key ID: 781C A3E2 C6ED 70A6 B356  7AF5 B510 542E D460 5CAE
       "The Internet should always be the Wild West!"

Back to alt.os.linux.slackware | Previous | NextNext in thread | Find similar | Unroll thread


Thread

countmail.py jayjwa <jayjwa@atr2.ath.cx.invalid> - 2026-06-01 22:54 -0400
  Re: countmail.py Eli the Bearded <*@eli.users.panix.com> - 2026-06-02 03:17 +0000
    Re: countmail.py jayjwa <jayjwa@atr2.ath.cx.invalid> - 2026-06-02 11:28 -0400
    Re: countmail.py (v2.1) jayjwa <jayjwa@atr2.ath.cx.invalid> - 2026-06-02 17:05 -0400

csiph-web