• countmail.py

    From jayjwa@jayjwa@atr2.ath.cx.invalid to alt.os.linux.slackware on Mon Jun 1 22:54:38 2026
    From Newsgroup: alt.os.linux.slackware

    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!"
    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From Eli the Bearded@*@eli.users.panix.com to alt.os.linux.slackware on Tue Jun 2 03:17:33 2026
    From Newsgroup: alt.os.linux.slackware

    In alt.os.linux.slackware, jayjwa <jayjwa@atr2.ath.cx.invalid> wrote:
    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.

    This doesn't work with maildirs. (NB: I am unfamiliar with "BSD
    countmail". I use my own implementation of "frm", but not often,
    preferring a "checkmail" script that tells me the latest message in
    a group of mail boxes and works by parsing the procmail log for
    delivery details instead of looking at the actual mail boxes. This
    prevents reading the message from resetting the mail file atime.

    #!/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
    [snip]
    # 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]' )

    I have _immediate_ red flags going up. I don't know specifics of how
    Python's "re.compile" works, but in normal Unix regex language the
    "[^Mail System Internal Data]" bit is a character class that contains
    the invert of the characters within. I am dubious that Python has
    redefined what "[^...]" means.

    Elijah
    ------
    doesn't care much how _many_ messages there are
    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From jayjwa@jayjwa@atr2.ath.cx.invalid to alt.os.linux.slackware on Tue Jun 2 11:28:16 2026
    From Newsgroup: alt.os.linux.slackware

    Eli the Bearded <*@eli.users.panix.com> writes:

    This doesn't work with maildirs.
    I don't use them and thus have nothing to work on. I'd consider adding
    support if there was interest. This is the discussion and the script I
    replaced in question: https://www.linuxquestions.org/questions/slackware-14/countmail-4175764150/

    mailPattern = re.compile( r'^From: *[^Mail System Internal Data]' )

    I have _immediate_ red flags going up. I don't know specifics of how
    Python's "re.compile" works
    That's the problem.

    "[^Mail System Internal Data]" bit is a character class that contains
    the invert of the characters within. I am dubious that Python has
    redefined what "[^...]" means.
    It has not.
    https://docs.python.org/3/library/re.html
    "Mail System Internal Data" is not a real mail message and thus should
    *not* be counted. When I start Alpine with no mail, Alpine shows "no
    mail", yet BSD countmail lists one message. That is incorrect. All this
    is explained in the script.
    --
    PGP Key ID: 781C A3E2 C6ED 70A6 B356 7AF5 B510 542E D460 5CAE
    "The Internet should always be the Wild West!"
    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From jayjwa@jayjwa@atr2.ath.cx.invalid to alt.os.linux.slackware on Tue Jun 2 17:05:05 2026
    From Newsgroup: alt.os.linux.slackware

    Eli the Bearded <*@eli.users.panix.com> writes:

    This doesn't work with maildirs. (NB: I am unfamiliar with "BSD
    countmail".
    I don't think the original countmail worked for Maildir. "frm" seems
    like it should, but doesn't work here. mutt -f ~/Mail does. This is what
    I'm working off of.

    Since I don't use Maildir myself, I had to construct some test
    data. This is what I think a Maildir area looks like:
    tree ~/Mail
    /home/jayjwa/Mail
    roLroCroC cur
    roLroCroC drafts
    roLroCroC new
    roe-a-a roLroCroC 1464003587.H805375P95754.gator3018.hostgator.com, S=20238_2,S:2,
    roe-a-a roLroCroC 1564003587.H805375P95754.gator3018.hostgator.com, S=20238_2,S:2,
    roe-a-a roLroCroC 1664003587.H805375P95754.gator3018.hostgator.com, S=20238_2,S:2,
    roe-a-a rooroCroC 9datatest
    rooroCroC tmp

    5 directories, 4 files

    As I understand it, "new" is the place new message land. "cur" is old so
    we don't count those. dotfiles are to be ignored. If a file is in
    Maildir but does not contain the regex match it's ignored.

    This is version 2.1 of the script, which now handles Maildir. If there's
    no Mail, Maildir or MAILDIR set, it falls back to mbox as before. If the
    user asks specifically for Maildir but it's not there, it's an error.

    env MAILDIR=/home/jayjwa/Mail python3 countmail.py
    THREE!

    Three mail messages!
    HaHaHaHaHa!

    mv Mail HideMail
    env MAILDIR=/home/jayjwa/Mail python3 countmail.py
    No mail in maildir /home/jayjwa/Mail/new/. Exiting.

    python3 countmail.py
    ONE!

    One mail message!
    HaHaHaHaHa!

    #!/usr/bin/python3
    ## countmail.py
    ## Rewrite of BSD countmail in basic Python3 to not use external tools
    ## and correctly handle Al/pine placeholder mails. Cross-platform for
    ## Linux, SunOS, and probably others with Python3.
    ## Works with maildir or mbox. If maildir (~/Mail, etc ) is found,
    ## this script assumes the user prefers it over mbox. maildir is
    ## settable, but must contain the subdirectory "/new/". If there's
    ## no maildir, look for mbox in the standard places.
    ## Ref:
    ## https://en.wikipedia.org/wiki/Maildir
    ## https://www.systoolsgroup.com/maildir/
    ## https://cr.yp.to/proto/maildir.html
    ## https://untroubled.org/ezmlm/man/man5/maildir.5.html
    ##
    ## $Id: countmail.py,v 2.1 2026/06/02 20:43:28 jayjwa Exp $
    import os, sys, re

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

    # 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]' )

    # Initialize mail count accumulator to zero.
    count = 0

    # 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 )

    ## [ maildir code ] --------------------------------------------
    # First, check if MAILDIR is set or if ~/{Mail,Maildir} exists.
    # If so, we assume this user has moved to maildir format and
    # to prefer it over mbox.

    # env MAILDIR=/home/you/Mail python3 countmail.py, if mail in ~/Mail
    maildir = os.getenv( 'MAILDIR' )
    if not maildir:
    # ~/Mail is common. Check for this first, then Maildir. The
    # base location is HOME so use this instead of LOGNAME.
    if os.path.isdir( f"{os.getenv( 'HOME' )}/Mail"):
    maildir = f"{os.getenv( 'HOME' )}/Mail"
    elif os.path.isdir( f"{os.getenv( 'HOME' )}/Maildir"):
    maildir = f"{os.getenv( 'HOME' )}/Maildir"
    else:
    ## [mbox code] ------------------------------------------------
    # Next, try to locate the user's mbox mail file. Respect env var,
    # then search the file system.
    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}" )

    # Assume mailPattern is a mail occurance and count it.
    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 the message and exit.
    print( f"{GREEN}{ integerToWords( count ).upper() }!{NC}\n\n{GREEN}{ integerToWords( count ).capitalize() } mail message{suffix}!{NC}" )
    print( f"{BLUE}HaHaHaHaHa!{NC}" )
    sys.exit()

    # At this point, the script is executing in Maildir mode.

    # maildir is base, subdir /new/ is where the files live to scan.
    # Construct full path.
    maildir = maildir + "/new/"

    # Walk maildir/new, excluding dotfiles, for files. Each is a
    # possible mail message. Not assuming, the script checks with its
    # regex before calling it one.
    if not os.path.isdir( maildir ):
    # The user asked to use Maildir functionality but it's not there.
    # Don't go looking for mbox in this case.
    sys.exit( f"{RED}No mail in maildir {maildir}. Exiting.{NC}" )

    for maildirFile in os.listdir( maildir ):
    # Disregard any dotfiles that might be in there.
    if not maildirFile.startswith( '.' ):
    # Assume mailPattern is a mail occurance and count them.
    with open( f"{maildir}{maildirFile}", 'r' ) as mdf:
    for line in mdf:
    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!"
    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From jayjwa@jayjwa@atr2.ath.cx.invalid to alt.os.linux.slackware on Mon Jul 20 14:22:59 2026
    From Newsgroup: alt.os.linux.slackware

    It looks like I misjudged the difficulty of the problem. Mail in email
    mailing list "digest" mode was causing a count that was too high. So my
    script was doing the wrong thing but with a usually (but not always)
    correct output. Ditto for removing the Alpine placeholder mail which was negating on "M" but not "Mail System Internal Data".

    import re
    pattern = re.compile( r'Needle' )
    re.match( pattern, "Needle in a hay stack" )
    <re.Match object; span=(0, 6), match='Needle'>
    pattern = re.compile( r'Needle in a hay [^stack]' )
    re.match( pattern, "Needle in a hay stack" )

    pattern = re.compile( r'Needle in a hay [^sausage]' )
    re.match( pattern, "Needle in a hay stack" )


    So, [^] will negate a match but it won't dismatch an entire line
    enclosed in "[]". Apologies to Eli. Maybe there's a way to put "()" in
    there but my re wushu isn't that powerful yet.

    pattern = re.compile( r'Needle in a hay [^s]' )
    re.match( pattern, "Needle in a hay stack" )


    I changed the algorith to track mail headers, not just look at "From: ",
    which makes it more robust. I looked at Elm's realfrom() and I think
    that's what it was doing. Fun fact: Not all MTAs give "Message-ID:" - Sendmail/mailx on Sun does "Message-Id:". Let's try this again, v2.2.


    #!/usr/bin/python3
    ## countmail.py
    ## Rewrite of BSD countmail in basic Python3 to not use external tools
    ## and correctly handle (Al)pine placeholder mails. Cross-platform for
    ## Linux, SunOS, and probably others with Python3.
    ## Works with maildir or mbox. If maildir (~/Mail, etc ) is found,
    ## this script assumes the user prefers it over mbox. maildir is
    ## settable, but must contain the subdirectory "/new/". If there's
    ## no maildir, look for mbox in the standard places.
    ## Ref:
    ## https://en.wikipedia.org/wiki/Maildir
    ## https://www.systoolsgroup.com/maildir/
    ## https://cr.yp.to/proto/maildir.html
    ## https://untroubled.org/ezmlm/man/man5/maildir.5.html
    ##
    ## $Id: countmail.py,v 2.2 2026/07/20 17:29:07 jayjwa Exp $
    import os, sys, re

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

    # Regex to indicate that there is a mail message in the mail file. In mbox
    # mode, we need to track when we are in a possible mail header to avoid
    # thinking any sentence in an email beginning with "From " is another mail.
    # Mail in mailing list "digest mode" can also cause an incorrect total.
    # Track with boolean flags, below.
    mailPattern = re.compile( r'^From ' )
    fromSeen = False
    messageIDSeen = False

    # Initialize mail count accumulator to zero.
    count = 0

    # 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 )

    ## [ maildir code ] --------------------------------------------
    # First, check if MAILDIR is set or if ~/{Mail,Maildir} exists.
    # If so, we assume this user has moved to maildir format and
    # to prefer it over mbox.

    # env MAILDIR=/home/you/Mail python3 countmail.py, if mail in ~/Mail
    maildir = os.getenv( 'MAILDIR' )
    if not maildir:
    # ~/Mail is common. Check for this first, then Maildir. The
    # base location is HOME so use this instead of LOGNAME.
    if os.path.isdir( f"{os.getenv( 'HOME' )}/Mail"):
    maildir = f"{os.getenv( 'HOME' )}/Mail"
    elif os.path.isdir( f"{os.getenv( 'HOME' )}/Maildir"):
    maildir = f"{os.getenv( 'HOME' )}/Maildir"
    else:
    ## [mbox code] ------------------------------------------------
    # Next, try to locate the user's mbox mail file. Respect env var,
    # then search the file system.
    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}" )

    # Assume mailPattern is a mail occurance and count it, but only if
    # we are tracking a mail header. That is, we need a "From " and
    # then a "Message-ID: ", in that order.
    with open( mailfile, 'r' ) as mf:
    for line in mf:
    # Only enter here on pattern match OR tracking pattern match
    if re.match( mailPattern, line ) or fromSeen:
    fromSeen = True
    # Linux does "Message-ID:" but Sun does "Message-Id:".
    # Message-Id: <202607182008.66IK8xfs004098@ibushi.lan>
    # from mailx/Sendmail, SunOS 5.11 (OI).
    if re.match( '^Message-I[Dd]: ', line ):
    messageIDSeen = True
    if fromSeen and messageIDSeen:
    # Add to count and reset flags
    count += 1
    fromSeen = False
    messageIDSeen = False
    # This isn't a real mail, but a placeholder from (Al)pine.
    # It will (falsely) increase our total. Subtract if found.
    if re.match( "From: Mail System Internal Data", 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 the message and exit.
    print( f"{GREEN}{ integerToWords( count ).upper() }!{NC}\n\n{GREEN}{ integerToWords( count ).capitalize() } mail message{suffix}!{NC}" )
    print( f"{BLUE}HaHaHaHaHa!{NC}" )
    sys.exit()

    # At this point, the script is executing in Maildir mode.

    # maildir is base, subdir /new/ is where the files live to scan.
    # Construct full path.
    maildir = maildir + "/new/"

    # Walk maildir/new, excluding dotfiles, for files. Each should be a
    # mail message.
    if not os.path.isdir( maildir ):
    # The user asked to use Maildir functionality but it's not there.
    # Don't go looking for mbox in this case.
    sys.exit( f"{RED}No mail in maildir {maildir}. Exiting.{NC}" )

    for maildirFile in os.listdir( maildir ):
    # Disregard any dotfiles that might be in there. Maildir is one
    # file equals one email.
    if not maildirFile.startswith( '.' ):
    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!"
    --- Synchronet 3.22a-Linux NewsLink 1.2