Archiving all bash commands typed

This one’s a quickie. Just a second of my config to record all bash commands to a file (.bash_eternal_history) forever. The default bash HISTFILESIZE is 500. Setting it to a non-numeric value will make the history file grow forever (although not your actual history size, which is controlled by HISTSIZE).

I do this in addition:

#~/.bash.d/eternal-history
# don't put duplicate lines in the history
HISTCONTROL=ignoredups
# append to the history file, don't overwrite it
shopt -s histappend
# for setting history length see HISTSIZE and HISTFILESIZE in bash(1)
HISTFILESIZE=infinite
# Creates an eternal bash log in the form
# PID USER INDEX TIMESTAMP COMMAND
export HISTTIMEFORMAT="%s "

PROMPT_COMMAND="${PROMPT_COMMAND:+$PROMPT_COMMAND ; }"'echo $$ $USER \
"$(history 1)" >> ~/.bash_eternal_history'
Tagged , , ,

Mail filtering with Dovecot

This expands on my previous post about how to set up an email server.

We’re going to set up a few spam filters in Dovecot under Debian. We’re going to use Sieve, which lets the user set up whichever filters they want. However, we’re going to run a couple pre-baked spam filters regardless of what the user sets up.

  1. Install Sieve.

    sudo apt-get install dovecot-sieve dovecot-managesieved
    
  2. Add Sieve to Dovecot

    # /etc/dovecot/dovecot.conf
    # Sieve and ManageSieve
    protocols = $protocols sieve
    protocol lmtp {
     mail_plugins = $mail_plugins sieve
    }
    service managesieve-login {
     inet_listener sieve {
     port = 4190
     }
    }
    protocol sieve {
     managesieve_logout_format = bytes ( in=%i : out=%o )
    }
    plugin {
     # Settings for the Sieve and ManageSieve plugin
     sieve = file:~/sieve;active=~/.dovecot.sieve
     sieve_before = /etc/dovecot/sieve.d/
     sieve_dir = ~/sieve # For old version of ManageSieve
     #sieve_extensions = +vnd.dovecot.filter
     #sieve_plugins = sieve_extprograms
    }
    
  3. Install and update SpamAssassin, a heuristic perl script for spam filtering.

    sudo apt-get install spamasssassin
    sudo sa-update
    
    # /etc/default/spamassassin
    ENABLED=1
    #CRON=1 # Update automatically
    
    # /etc/spamassassin/local.cf
    report_safe 0 # Don't modify headers
    
    sudo service spamassassin start
    
  4. There’s a lot of custom configuration and training you should do to get SpamAssassin to accurately categorize what you consider spam. I’m including a minimal amount here. The following will train SpamAssassin system-wide based on what users sort into spam folders.

    #!/bin/sh
    # /etc/cron.daily/spamassassin-train
    all_folders() {
            find /var/mail/vmail -type d -regextype posix-extended -regex '.*/cur|new$'
    }
    
    all_folders | grep "Spam" | sa-learn --spam -f - >/dev/null 2>/dev/null
    all_folders | grep -v "Spam" | sa-learn --ham -f - >/dev/null 2>/dev/null
    
  5. Make Postfix run SpamAssassin as a filter, so that it can add headers as mail comes in.

    # /etc/postfix/master.cf
    smtp inet n - - - - smtpd
     -o content_filter=spamassassin
    # ...
    spamassassin unix - n n - - pipe user=debian-spamd argv=/usr/bin/spamc -f -e /usr/sbin/sendmail -oi -f ${sender} ${recipient}
    
    sudo service postfix restart
    
  6. Add SpamAssassin to Sieve. Dovecot (via Sieve) will now move messages with spam headers from SpamAssassin to your spam folder. Make sure you have a “Spam” folder and that it’s set to autosubscribe.

    # /etc/dovecot/sieve.d/spam-assassin.sieve
    require ["fileinto"];
    # Move spam to spam folder
    if header :contains "X-Spam-Flag" "YES" {
     fileinto "Spam";
     # Stop here - if there are other rules, ignore them for spam messages
     stop;
    }
    
    cd /etc/dovecot/sieve.d
    sudo sievec spam-assassin.sieve
    
  7. Restart Dovecot

    sudo service dovecot restart
    
  8. Test spam. The GTUBE is designed to definitely get rejected. Set the content of your email to this:

    XJS*C4JDBQADN1.NSBN3*2IDNEN*GTUBE-STANDARD-ANTI-UBE-TEST-EMAIL*C.34X
    
  9. You should also be able to create user-defined filters in Sieve, via the ManageSieve protocol. I tested this using a Sieve thunderbird extension. You’re on your own here.

Tagged , , , , ,

Installing email with Postfix and Dovecot (with Postgres)

I’m posting my email setup here. The end result will:

  • Use Postfix for SMTP
  • Use Dovecot for IMAP and authentication
  • Store usernames, email forwards, and passwords in a Postgres SQL database
  • Only be accessible over encrypted channels
  • Pass all common spam checks
  • Support SMTP sending and IMAP email checking. I did not include POP3 because I don’t use it, but it should be easy to add
  • NOT add spam filtering or web mail (this article is long enough as it is, maybe in a follow-up)

Note: My set up is pretty standard, except that rDNS for smtp.za3k.com resolves to za3k.com because I only have one IP. You may need to change your hostnames if you’re using mail.example.com or smtp.example.com.

On to the install!

  1. Install debian packages

    sudo apt-get install postfix # Postfix \
          dovecot-core dovecot-imapd dovecot-lmtpd # Dovecot \
          postgresql dovecot-pgsql postfix-pgsql # Postgres \
          opendkim opendkim-tools # DKIM
    
  2. Set up security. smtp.za3k.com cert is at /etc/certs/zak3.com.pem, the key is at /etc/ssl/private/smtp.za3k.com.key. dhparams for postfix are at /etc/postfix/dhparams.pem. (If you need a certificate and don’t know how to get one, you can read Setting up SSL certificates using StartSSL)

  3. Install Postfix

    # /etc/postfix/master.cf
    smtp       inet  n       -       -       -       -       smtpd
    submission inet  n       -       -       -       -       smtpd
      -o syslog_name=postfix/submission
      -o smtpd_tls_security_level=encrypt
      -o smtpd_sasl_auth_enable=yes
      -o smtpd_reject_unlisted_recipient=no
      -o milter_macro_daemon_name=ORIGINATING
    
    # /etc/postfix/main.cf additions
    # TLS parameters
    smtpd_tls_cert_file=/etc/ssl/certs/smtp.za3k.com.pem
    smtpd_tls_key_file=/etc/ssl/private/smtp.za3k.com.key
    smtpd_use_tls=yes
    smtpd_tls_mandatory_protocols=!SSLv2,!SSLv3
    smtp_tls_mandatory_protocols=!SSLv2,!SSLv3
    smtpd_tls_protocols=!SSLv2,!SSLv3
    smtp_tls_protocols=!SSLv2,!SSLv3
    smtpd_tls_exclude_ciphers = aNULL, eNULL, EXPORT, DES, RC4, MD5, PSK, aECDH, EDH-DSS-DES-CBC3-SHA, EDH-RSA-DES-CDC3-SHA, KRB5-DE5, CBC3-SHA
    
    # Relay and recipient settings
    myhostname = za3k.com
    myorigin = /etc/mailname
    mydestination = za3k.com, smtp.za3k.com, localhost.com, localhost
    relayhost =
    mynetworks_style = host
    mailbox_size_limit = 0
    inet_interfaces = all
    smtpd_relay_restrictions = permit_mynetworks,
      permit_sasl_authenticated,
      reject_unauth_destination
    
    alias_maps = hash:/etc/aliases
    local_recipient_maps = $alias_maps
    mailbox_transport = lmtp:unix:private/dovecot-lmtp
    
  4. Install Dovecot

    # /etc/dovecot/dovecot.cf
    mail_privileged_group = mail # Local mail
    disable_plaintext_auth = no
    
    protocols = imap
    
    ssl=required
    ssl_cert = </etc/ssl/certs/imap.za3k.com.pem
    ssl_key = </etc/ssl/private/imap.za3k.com.key
    
    # IMAP Folders
    namespace {
     inbox = yes
     mailbox Trash {
     auto = create
     special_use = \Trash
     }
     mailbox Drafts {
     auto = no
     special_use = \Drafts
     }
     mailbox Sent {
     auto = subscribe
     special_use = \Sent
     }
     mailbox Spam {
     auto = subscribe
     special_use = \Junk
     }
    }
    
    # Expunging / deleting mail should FAIL, use the lazy_expunge plugin for this
    namespace {
     prefix = .EXPUNGED/
     hidden = yes
     list = no
     location = maildir:~/expunged
    }
    mail_plugins = $mail_plugins lazy_expunge
    plugin {
     lazy_expunge = .EXPUNGED/
    }
    
    # /etc/postfix/main.cf
    # SASL authentication is done through Dovecot to let users relay mail
    smtpd_sasl_type = dovecot
    smtpd_sasl_path = private/auth
    
  5. Set up the database and virtual users. Commands

    # Create the user vmail for storing virtual mail
    # vmail:x:5000:5000::/var/mail/vmail:/usr/bin/nologin
    groupadd -g 5000 vmail
    mkdir /var/mail/vmail
    useradd -M -d /var/mail/vmail --shell=/usr/bin/nologin -u 5000 -g vmail vmail
    chown vmail:vmail /var/mail/vmail
    chmod 700 /var/mail/vmail
    
    psql -U postgres
    ; Set up the users
    CREATE USER 'postfix' PASSWORD 'XXX';
    CREATE USER 'dovecot' PASSWORD 'XXX';
    
    ; Create the database
    CREATE DATABASE email;
    \connect email
    
    ; Set up the schema 
    
    CREATE TABLE aliases (
        alias text NOT NULL,
        email text NOT NULL
    );
    
    CREATE TABLE users (
        username text NOT NULL,
        domain text NOT NULL,
        created timestamp with time zone DEFAULT now(),
        password text NOT NULL
    );
    
    REVOKE ALL ON TABLE aliases FROM PUBLIC;
    GRANT ALL ON TABLE aliases TO postfix;
    GRANT ALL ON TABLE aliases TO dovecot;
    
    REVOKE ALL ON TABLE users FROM PUBLIC;
    GRANT ALL ON TABLE users TO dovecot;
    GRANT ALL ON TABLE users TO postfix;
    
    # /etc/dovecot/dovecot.conf
    # Since we're giving each virtual user their own directory under /var/mail/vmail, just use that directly and not a subdirectory
    mail_location = maildir:~/
    
    # /etc/dovecot/dovecot-sql.conf defines the DB queries used for authorization
    passdb {
      driver = sql
      args = /etc/dovecot/dovecot-sql.conf
    }
    userdb {
      driver = prefetch
    }
    userdb {
      driver = sql
      args = /etc/dovecot/dovecot-sql.conf
    }
    
    # /etc/postfix/main.cf
    pgsql:/etc/postfix/pgsql-virtual-aliases.cf
    local_recipient_maps = pgsql:/etc/postfix/pgsql-virtual-mailbox.cf 
    
    # /etc/postfix/pgsql-virtual-aliases.cf
    # hosts = localhost
    user = postfix
    password = XXXXXX
    dbname = email
    
    query = SELECT email FROM aliases WHERE alias='%s'
    
    # /etc/postfix/pgsql-virtual-mailbox.cf
    # hosts = localhost
    user = postfix
    password = XXXXXX
    dbname = email
    
    query = SELECT concat(username,'@',domain,'/') as email FROM users WHERE username='%s'
    
    # /etc/dovecot/dovecot-sql.conf
    driver = pgsql
    connect = host=localhost dbname=email user=dovecot password=XXXXXX
    default_pass_scheme = SHA512
    password_query = SELECT \
      CONCAT(username,'@',domain) as user, \
      password, \
      'vmail' AS userdb_uid, \
      'vmail' AS userdb_gid, \
      '/var/mail/vmail/%u' as userdb_home \
      FROM users \
      WHERE concat(username,'@',domain) = '%u';
    
    user_query = SELECT username, \
      CONCAT('maildir:/var/mail/vmail/',username,'@',domain) as mail, \
      '/var/mail/vmail/%u' as home, \
      'vmail' as uid, \
      'vmail' as gid \
      FROM users \
      WHERE concat(username,'@',domain) = '%u';
    
  6. Set up users. Example user creation:

    # Generate a password
    $ doveadm pw -s sha512 -r 100
    Enter new password: ...
    Retype new password: ...
    {SHA512}.............................................................==
    
    psql -U dovecot -d email
    ; Create a user za3k@za3k.com
    mail=# INSERT INTO users (
        username,
        domain,
        password
    ) VALUES (
        'za3k',
        'za3k.com'
        '{SHA512}.............................................................==',
    );
    
  7. Set up aliases/redirects. Example redirect creation:

    psql -U dovecot -d email
    ; Redirect mail from foo@example.com to bar@example.net
    mail=# INSERT INTO users ( email, alias ) VALUES (
        'bar@example.net',
        'foo@example.com'
    );
    
  8. Test setup locally by hand. Try using TELNET. Test remote setup using STARTSSL. This is similar to the previous step, but to start the connection use:

    openssl s_client -connect smtp.za3k.com:587 -starttls smtp
    

    Make sure to test email to addresses at your domain or that you’ve set up (final destination), and emails you’re trying to send somewhere else (relay email)

    A small digression: port 25 is used for unencrypted email and support STARTTLS, 587 is used for STARTTLS only, and 465 (obsolete) is used for TLS. My ISP, Comcast, blocks access to port 25 on outgoing traffic.

  9. Make sure you’re not running an open relay at http://mxtoolbox.com/diagnostic.aspx

  10. Set your DNS so that the MX record points at your new mailserver. You’ll probably want a store and forward backup mail server (mine is provided by my registrar). Email should arrive at your mail server from now on. This is the absolute minimum setup. Everything from here on is to help the community combat spam (and you not to get blacklisted).
  11. Set up DKIM (DomainKeys Identified Mail). DKIM signs outgoing mail to show that it’s from your server, which helps you not get flagged as spam.
    None of these files or folders exist to begin with in debian.

    # Add to /etc/opendkim.conf
    KeyTable                /etc/opendkim/KeyTable
    SigningTable            /etc/opendkim/SigningTable
    ExternalIgnoreList      /etc/opendkim/TrustedHosts
    InternalHosts           /etc/opendkim/TrustedHosts
    LogWhy yes
    
    # /etc/opendkim/TrustedHosts
    127.0.0.1
    [::1]
    localhost
    za3k.com
    smtp.za3k.com
    
    mkdir -p /etc/opendkim/keys/za3k.com
    cd /etc/opendkim/keys/za3k.com
    opendkim-genkey -s default -d za3k.com
    chown opendkim:opendkim default.private
    
    # /etc/opendkim/KeyTable
    default._domainkey.za3k.com za3k.com:default:/etc/opendkim/keys/za3k.com/default.private
    
    # /etc/opendkim/SigningTable
    za3k.com default._domainkey.za3k.com
    

    Display the DNS public key to set in a TXT record with:

    # sudo cat /etc/opendkim/keys/za3k.com/default.txt
    default._domainkey      IN      TXT     ( "v=DKIM1; k=rsa; "
              "p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCggdv3OtQMek/fnu+hRrHYZTUcpUFcSGL/+Sbq+GffR98RCgabx/jjPJo3HmqsB8czaXf7yjO2UiSN/a8Ae6/yu23d7hyTPUDacatEM+2Xc4/zG+eAlAMQOLRJeo3z53sNiq0SmJET6R6yH4HCv9VkuS0TQczkvME5hApft+ZedwIDAQAB" )  ; ----- DKIM
    
    # My registrar doesn't support this syntax so it ends up looking like: 
    $ dig txt default._domainkey.za3k.com txt
    default._domainkey.za3k.com. 10800 IN   TXT     "v=DKIM1\; k=rsa\; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCggdv3OtQMek/fnu+hRrHYZTUcpUFcSGL/+Sbq+GffR98RCgabx/jjPJo3HmqsB8czaXf7yjO2UiSN/a8Ae6/yu23d7hyTPUDacatEM+2Xc4/zG+eAlAMQOLRJeo3z53sNiq0SmJET6R6yH4HCv9VkuS0TQczkvME5hApft+ZedwIDAQAB"
    
    # Uncomment in /etc/default/opendkim
    SOCKET="inet:12345@localhost" # listen on loopback on port 12345
    
    # /etc/postfix/main.cf
    # DKIM
    milter_default_action = accept
    milter_protocol = 6
    smtpd_milters = inet:localhost:12345
    non_smtpd_milters = inet:localhost:12345
    
  12. Set up SPF (Sender Policy Framework). SPF explains to other services which IPs can send email on your behalf. You can set up whatever policy you like. A guide to the syntax is at: http://www.openspf.org/SPF_Record_Syntax.  Mine is

    @ 10800 IN TXT "v=spf1 +a:za3k.com +mx:za3k.com ~all"
    

    You should also be verifying this on your end as part of combating spam, but as far as outgoing mail all you need to do is add a TXT record to your DNS record.

  13. Set your rDNS (reverse DNS) if it’s not already. This should point at the same hostname reported by Postfix during SMTP. This will be handled by whoever assigns your IP address (in my case, my hosting provider).

  14. Test your spam reputability using https://www.mail-tester.com or https://www.port25.com/support/authentication-center/email-verification. You can monitor if you’re on any blacklists at http://mxtoolbox.com/blacklists.aspx.
  15. Set up DMARC. DMARC declares your policy around DKIM being mandatory. You can set up whatever policy you like.  Mine is

    _dmarc 10800 IN TXT "v=DMARC1;p=reject;aspf=s;adkim=s;pct=100;rua=mailto:postmaster@za3k.com"
    

My sources writing this:

Takeaways

  • You can set up store-and-forward mail servers, so if your mail server goes down, you don’t lose all the email for that period. It’s generally a free thing.
  • Postfix’s configuration files were badly designed and crufty, so you might pick a different SMTP server.
  • Email was REALLY not designed to do authentication, which is why proving you’re not a spammer is so difficult. This would all be trivial with decent crypto baked in (or really, almost any backwards-incompatible change)
  • The option to specify a SQL query as a configuration file option is wonderful. Thanks, Dovecot.
  • Overall, although it was a lot of work, I do feel like it was worth it to run my own email server.
Tagged , , , , ,

Archiving Twitch

Install jq and youtube-dl

Get a list of the last 100 URLs:

curl https://api.twitch.tv/kraken/channels/${TWITCH_USER}/videos?broadcasts=true&limit=100 | 
  jq -r '.videos[].url' > past_broadcasts.txt

Save them locally:

youtube-dl -a past_broadcasts.txt -o "%(upload_date)s.%(title)s.%(id)s.%(ext)s"

Did it. youtube-dl is smart enough to avoid re-downloading videos it already has, so as long as you run this often enough (I do daily), you should avoid losing videos before they’re deleted.

Thanks jrayhawk for the API info.

Tagged , , ,

Linux Print Server

So have you ever used a web printer and it was great?

Yeah, me neither. It’s probably possible on windows, but try to add more than one OS to the network and it’s horrible. And actually printing is a major pain in Linux anyway. Theoretically ‘lp’ and the like have no problem with remote printers, but I wanted something I understood. So today I’m going to post my setup I use instead.

I have a computer physically connected to the printer. Let’s call it ‘printserver’. On that server there is a folder, /printme, which is constantly monitored by inode. Any file added to that directory is printed.

Suppose I downloaded cutecats.pdf and I want to print it. Then I run:

scp cutecats.pdf printserver:/printme

And voila, the cute cats get printed.


Here’s the setup for the server:

  1. Get the printer to work. This is the hard step.
  2. Make a directory /printme. Add any missing users, add a new group called ‘print’ and add everyone who needs to print to that, etc.
  3. Set up /printme to be a tmpfs with the sticky bit set. (So we don’t fill up the hard drive)

    /etc/fstab
    tmpfs           /printme        tmpfs   rw,nodev,nosuid,noexec,uid=nobody,gid=print,mode=1770,size=1G  0       0
    
  4. Install incron and add this to the incrontab (of user ‘print’ or ‘sudo’):

    # incrontab -l
    /printme IN_CLOSE_WRITE,IN_MOVED_TO lp $@/$#
    

    Note that this will preserve files after they’re printed, because my server is low-volume enough I don’t need to care.

Tagged , ,

Installing Canon imageClass LBP-6000 on 64-bit Debian

(From Stack Overflow)

  1. 64 bit requirements for pre-made binaries:

    sudo dpkg --add-architecture i386
    sudo apt-get update
    sudo apt-get install libstdc++6:i386 libxml2:i386 zlib1g:i386 libpopt0:i386
    
  2. Install CUPS

    sudo apt-get update
    sudo apt-get install cups
    
  3. Download DriverGo to http://support-au.canon.com.au/contents/AU/EN/0100459602.html and download driver

    64e2d00f0c8764d4032687d29e88f06727d88825 Linux_CAPT_PrinterDriver_V270_uk_EN.tar.gz
    
  4. Extract and enter extracted folder

    tar xf Linux_CAPT_PrinterDriver_V270_uk_EN.tar.gz
    cd Linux_CAPT_PrinterDriver_V270_uk_EN
    
  5. Install the custom drivers and ccpd

    sudo dpkg -i 64-bit_Driver/Debian/*.deb
    
  6. Add the printer to CUPS and ccpd

    sudo lpadmin -p CANON_LBP6000 -m CNCUPSLBP6018CAPTS.ppd -v ccp://localhost:59687
    sudo lpadmin -p CANON_LBP6000 -E
    
    sudo ccpdadmin -p CANON_LBP6000 -o /dev/usb/lp0
    
  7. Set the default printer

    sudo lpoptions -d CANON_LBP6000
    
  8. Set ccpd to start on boot

    sudo update-rc.d ccpd defaults
    
Tagged , , ,

Backup android on plugin

In a previous post I discussed how to backup android with rsync. In this post, I’ll improve on that solution so it happens when you plug the phone in, rather than manually. My solution happens to know I have only one phone; you should adjust accordingly.

The process is

  1. Plug the phone in
  2. Unlock the screen (you’ll see a prompt to do this).
  3. Backup starts automatically
  4. Wait for the backup to finish before unplugging

First, let’s add a udev rule to auto-mount the phone when it’s plugged in and unlocked, and run appropriate scripts.

# 10-android.rules
ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="18d1", ATTR{idProduct}=="4ee2", MODE="0660", GROUP="plugdev", SYMLINK+="android", RUN+="/usr/local/bin/android-connected"
ACTION=="remove", SUBSYSTEM=="usb", ENV{ID_MODEL}=="Nexus_4", RUN+="/usr/local/bin/android-disconnected"

Next, we’ll add android-connected and android-disconnected

#!/bin/bash
# /usr/local/bin/android-connected
if [[ "$1" != "-f" ]]
then
 echo "/usr/local/bin/android-connected -f" | /usr/bin/at now
 exit 0
fi

sudo -u zachary DISPLAY=:0 /usr/bin/notify-send "Android plugged in, please unlock."
sudo -u zachary /usr/local/bin/android-mountfs
sudo -u zachary DISPLAY=:0 /usr/bin/notify-send "Mounted, backing up..."
/usr/bin/flock /var/lock/phone-backup.pid sudo -u zachary /usr/local/bin/phone-backup-xenu
sudo -u zachary DISPLAY=:0 /usr/bin/notify-send "Backup completed."
# !/bin/sh
# /usr/local/bin/android-disconnected
#!/bin/sh
sudo -u zachary DISPLAY=:0 /usr/bin/notify-send "Android unplugged."
sudo -u zachary /usr/local/bin/android-umountfs

We’ll add something to mount and unmount the system. Keeping in mind that mounting only works when the screen is unlocked we’ll put that in a loop that checks if the mount worked:

#!/bin/sh
# /usr/local/bin/android-mountfs

android_locked()
{
ls /media/android 2>/dev/null >/dev/null
[ "$?" -eq 2 ]
}

jmtpfs /media/android # mount
while android_locked; do
  fusermount -u /media/android
  sleep 3
  jmtpfs /media/android # mount
done
#!/bin/sh
# /usr/local/bin/android-umountfs
fusermount -u /media/android

The contents of  /usr/local/bin/phone-backup are pretty me-specific so I’ll omit it, but it copies /media/android over to a server. (fun detail: MTP doesn’t show all information even on a rooted phone, so there’s more work to do)

Tagged , , ,

Screen and Tmux IDEs

I don’t usually like IDEs. They’re hard to switch off of, they do too much. They don’t let me customize things, and I always have to use external tools anyway. I’d really rather do things with a bunch of small tools, the linux way. The problem is, if I close everything, I’ll have trouble getting started back up again. Saving state is one solution. Quick start-up is another. Basically, write a checklist for myself to make starting things up easy (open such-and-such files in the editor, start the server in debug mode, etc).

But we’re programmers, so obviously we’re not going to use a literal checklist. Instead, we’re going to write a little script to auto-start things in a new screen session:

#!/usr/bin/screen -c
# game_development.screen.conf
# Run stand-alone or with screen -c game_devel.screen.conf
screen -t "Vim" 2 bash -c "vim -p *.t"
bind "r" screen -t "Game" 2 bash run.sh

Or if you prefer tmux:

# game_development.tmux.conf
# Run with tmux -f game_development.tmux.conf attach
new-session -s game_development
new-window -n "Vim" "bash -c 'vim -p *.t'"
bind r new-window -n "Game" "bash run.sh"

Note the main features being used: a shebang line hack for screen, to let this file be self-contained and executable. Opening files in vim in place of a text editor. Binding keys for unit tests, running the program, restarting the server, etc. Now, a similar approach is to add new key bindings to the text editor, but I feel like text editors should edit text, and I like being able to document all the additions with help menus (which screen and tmux both support).

Note: ratpoison is similar to screen/tmux so you can do similar things in X.

One thing I’d love is if this kind of file was easy to dump from the current state, especially for things like positioning windows, etc. A little assistance is available, but not too much. Ratpoison and tmux let you dump sizing information. Nothing outputs keybindings or a list of running programs with their windows.

There is a program called tmuxinator to let you write the same config in nested YAML of sessions, panes, and windows, which might appeal to some users.

Also, check out dtach if you don’t need panes and windows, and just want a detachable process.

Tagged , , , , , ,

Configuring mailx’s .mailrc with Gmail

Here’s how I added gmail to .mailrc for the BSD program mailx, provided by the s-nail package in arch.

account gmail {
  set folder=imaps://example@gmail.com@imap.gmail.com
  set password-example@gmail.com@imap.gmail.com="PASS"
  set smtp-use-starttls
  set smtp=smtp://smtp.gmail.com:587
  set smtp-auth=login
  set smtp-auth-user=example@gmail.com
  set smtp-auth-password="PASS"
  set from="John Smith <example@gmail.com>"
}

Replace PASS with your actual password, and example@gmail.com with your actual email. Read the documentation if you want to avoid plaintext passwords.

You can send mail with ‘mail -A gmail ’. If you have only one account, remove the first and last line and use ‘mail

Tagged , ,